diff --git a/.gitignore b/.gitignore index a67f2602..b2963011 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ /public /dist /.webpack +/open-fin-al/resources/neo4j-win/ +/open-fin-al/resources/jre-win/ # misc .DS_Store @@ -69,4 +71,1627 @@ trained_models/ results/ # wandb -wandb/ \ No newline at end of file +wandb/ +open-fin-al/resources/neo4j-mac/products/neo4j-genai-plugin-2026.01.4.jar +.gitignore +open-fin-al/resources/README.md +open-fin-al/resources/jre-mac/LICENSE +open-fin-al/resources/jre-mac/README +open-fin-al/resources/jre-mac/release +open-fin-al/resources/jre-mac/bin/jar +open-fin-al/resources/jre-mac/bin/jarsigner +open-fin-al/resources/jre-mac/bin/java +open-fin-al/resources/jre-mac/bin/javac +open-fin-al/resources/jre-mac/bin/javadoc +open-fin-al/resources/jre-mac/bin/javap +open-fin-al/resources/jre-mac/bin/jcmd +open-fin-al/resources/jre-mac/bin/jconsole +open-fin-al/resources/jre-mac/bin/jdb +open-fin-al/resources/jre-mac/bin/jdeprscan +open-fin-al/resources/jre-mac/bin/jdeps +open-fin-al/resources/jre-mac/bin/jfr +open-fin-al/resources/jre-mac/bin/jhsdb +open-fin-al/resources/jre-mac/bin/jimage +open-fin-al/resources/jre-mac/bin/jinfo +open-fin-al/resources/jre-mac/bin/jlink +open-fin-al/resources/jre-mac/bin/jmap +open-fin-al/resources/jre-mac/bin/jmod +open-fin-al/resources/jre-mac/bin/jnativescan +open-fin-al/resources/jre-mac/bin/jpackage +open-fin-al/resources/jre-mac/bin/jps +open-fin-al/resources/jre-mac/bin/jrunscript +open-fin-al/resources/jre-mac/bin/jshell +open-fin-al/resources/jre-mac/bin/jstack +open-fin-al/resources/jre-mac/bin/jstat +open-fin-al/resources/jre-mac/bin/jstatd +open-fin-al/resources/jre-mac/bin/jwebserver +open-fin-al/resources/jre-mac/bin/keytool +open-fin-al/resources/jre-mac/bin/rmiregistry +open-fin-al/resources/jre-mac/bin/serialver +open-fin-al/resources/jre-mac/conf/jaxp-strict.properties.template +open-fin-al/resources/jre-mac/conf/jaxp.properties +open-fin-al/resources/jre-mac/conf/logging.properties +open-fin-al/resources/jre-mac/conf/net.properties +open-fin-al/resources/jre-mac/conf/sound.properties +open-fin-al/resources/jre-mac/conf/management/jmxremote.access +open-fin-al/resources/jre-mac/conf/management/jmxremote.password.template +open-fin-al/resources/jre-mac/conf/management/management.properties +open-fin-al/resources/jre-mac/conf/security/java.security +open-fin-al/resources/jre-mac/conf/security/policy/README.txt +open-fin-al/resources/jre-mac/conf/security/policy/limited/default_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/limited/default_US_export.policy +open-fin-al/resources/jre-mac/conf/security/policy/limited/exempt_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/unlimited/default_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/unlimited/default_US_export.policy +open-fin-al/resources/jre-mac/include/classfile_constants.h +open-fin-al/resources/jre-mac/include/jawt.h +open-fin-al/resources/jre-mac/include/jdwpTransport.h +open-fin-al/resources/jre-mac/include/jni.h +open-fin-al/resources/jre-mac/include/jvmti.h +open-fin-al/resources/jre-mac/include/jvmticmlr.h +open-fin-al/resources/jre-mac/include/darwin/jawt_md.h +open-fin-al/resources/jre-mac/include/darwin/jni_md.h +open-fin-al/resources/jre-mac/jmods/java.base.jmod +open-fin-al/resources/jre-mac/jmods/java.compiler.jmod +open-fin-al/resources/jre-mac/jmods/java.datatransfer.jmod +open-fin-al/resources/jre-mac/jmods/java.desktop.jmod +open-fin-al/resources/jre-mac/jmods/java.instrument.jmod +open-fin-al/resources/jre-mac/jmods/java.logging.jmod +open-fin-al/resources/jre-mac/jmods/java.management.jmod +open-fin-al/resources/jre-mac/jmods/java.management.rmi.jmod +open-fin-al/resources/jre-mac/jmods/java.naming.jmod +open-fin-al/resources/jre-mac/jmods/java.net.http.jmod +open-fin-al/resources/jre-mac/jmods/java.prefs.jmod +open-fin-al/resources/jre-mac/jmods/java.rmi.jmod +open-fin-al/resources/jre-mac/jmods/java.scripting.jmod +open-fin-al/resources/jre-mac/jmods/java.se.jmod +open-fin-al/resources/jre-mac/jmods/java.security.jgss.jmod +open-fin-al/resources/jre-mac/jmods/java.security.sasl.jmod +open-fin-al/resources/jre-mac/jmods/java.smartcardio.jmod +open-fin-al/resources/jre-mac/jmods/java.sql.jmod +open-fin-al/resources/jre-mac/jmods/java.sql.rowset.jmod +open-fin-al/resources/jre-mac/jmods/java.transaction.xa.jmod +open-fin-al/resources/jre-mac/jmods/java.xml.crypto.jmod +open-fin-al/resources/jre-mac/jmods/java.xml.jmod +open-fin-al/resources/jre-mac/jmods/jdk.accessibility.jmod +open-fin-al/resources/jre-mac/jmods/jdk.attach.jmod +open-fin-al/resources/jre-mac/jmods/jdk.charsets.jmod +open-fin-al/resources/jre-mac/jmods/jdk.compiler.jmod +open-fin-al/resources/jre-mac/jmods/jdk.crypto.cryptoki.jmod +open-fin-al/resources/jre-mac/jmods/jdk.crypto.ec.jmod +open-fin-al/resources/jre-mac/jmods/jdk.dynalink.jmod +open-fin-al/resources/jre-mac/jmods/jdk.editpad.jmod +open-fin-al/resources/jre-mac/jmods/jdk.graal.compiler.jmod +open-fin-al/resources/jre-mac/jmods/jdk.graal.compiler.management.jmod +open-fin-al/resources/jre-mac/jmods/jdk.hotspot.agent.jmod +open-fin-al/resources/jre-mac/jmods/jdk.httpserver.jmod +open-fin-al/resources/jre-mac/jmods/jdk.incubator.vector.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.ed.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.jvmstat.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.le.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.md.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.opt.jmod +open-fin-al/resources/jre-mac/jmods/jdk.internal.vm.ci.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jartool.jmod +open-fin-al/resources/jre-mac/jmods/jdk.javadoc.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jcmd.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jconsole.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jdeps.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jdi.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jdwp.agent.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jfr.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jlink.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jpackage.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jshell.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jsobject.jmod +open-fin-al/resources/jre-mac/jmods/jdk.jstatd.jmod +open-fin-al/resources/jre-mac/jmods/jdk.localedata.jmod +open-fin-al/resources/jre-mac/jmods/jdk.management.agent.jmod +open-fin-al/resources/jre-mac/jmods/jdk.management.jfr.jmod +open-fin-al/resources/jre-mac/jmods/jdk.management.jmod +open-fin-al/resources/jre-mac/jmods/jdk.naming.dns.jmod +open-fin-al/resources/jre-mac/jmods/jdk.naming.rmi.jmod +open-fin-al/resources/jre-mac/jmods/jdk.net.jmod +open-fin-al/resources/jre-mac/jmods/jdk.nio.mapmode.jmod +open-fin-al/resources/jre-mac/jmods/jdk.sctp.jmod +open-fin-al/resources/jre-mac/jmods/jdk.security.auth.jmod +open-fin-al/resources/jre-mac/jmods/jdk.security.jgss.jmod +open-fin-al/resources/jre-mac/jmods/jdk.unsupported.desktop.jmod +open-fin-al/resources/jre-mac/jmods/jdk.unsupported.jmod +open-fin-al/resources/jre-mac/jmods/jdk.xml.dom.jmod +open-fin-al/resources/jre-mac/jmods/jdk.zipfs.jmod +open-fin-al/resources/jre-mac/legal/java.base/aes.md +open-fin-al/resources/jre-mac/legal/java.base/c-libutl.md +open-fin-al/resources/jre-mac/legal/java.base/cldr.md +open-fin-al/resources/jre-mac/legal/java.base/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.base/icu.md +open-fin-al/resources/jre-mac/legal/java.base/LICENSE +open-fin-al/resources/jre-mac/legal/java.base/public_suffix.md +open-fin-al/resources/jre-mac/legal/java.base/siphash.md +open-fin-al/resources/jre-mac/legal/java.base/unicode.md +open-fin-al/resources/jre-mac/legal/java.base/zlib.md +open-fin-al/resources/jre-mac/legal/java.compiler/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.compiler/LICENSE +open-fin-al/resources/jre-mac/legal/java.datatransfer/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.datatransfer/LICENSE +open-fin-al/resources/jre-mac/legal/java.desktop/colorimaging.md +open-fin-al/resources/jre-mac/legal/java.desktop/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.desktop/freetype.md +open-fin-al/resources/jre-mac/legal/java.desktop/giflib.md +open-fin-al/resources/jre-mac/legal/java.desktop/harfbuzz.md +open-fin-al/resources/jre-mac/legal/java.desktop/jpeg.md +open-fin-al/resources/jre-mac/legal/java.desktop/lcms.md +open-fin-al/resources/jre-mac/legal/java.desktop/libpng.md +open-fin-al/resources/jre-mac/legal/java.desktop/LICENSE +open-fin-al/resources/jre-mac/legal/java.desktop/mesa3d.md +open-fin-al/resources/jre-mac/legal/java.desktop/pipewire.md +open-fin-al/resources/jre-mac/legal/java.desktop/xwd.md +open-fin-al/resources/jre-mac/legal/java.instrument/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.instrument/LICENSE +open-fin-al/resources/jre-mac/legal/java.logging/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.logging/LICENSE +open-fin-al/resources/jre-mac/legal/java.management/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.management/LICENSE +open-fin-al/resources/jre-mac/legal/java.management.rmi/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.management.rmi/LICENSE +open-fin-al/resources/jre-mac/legal/java.naming/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.naming/LICENSE +open-fin-al/resources/jre-mac/legal/java.net.http/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.net.http/LICENSE +open-fin-al/resources/jre-mac/legal/java.prefs/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.prefs/LICENSE +open-fin-al/resources/jre-mac/legal/java.rmi/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.rmi/LICENSE +open-fin-al/resources/jre-mac/legal/java.scripting/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.scripting/LICENSE +open-fin-al/resources/jre-mac/legal/java.se/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.se/LICENSE +open-fin-al/resources/jre-mac/legal/java.security.jgss/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.security.jgss/LICENSE +open-fin-al/resources/jre-mac/legal/java.security.sasl/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.security.sasl/LICENSE +open-fin-al/resources/jre-mac/legal/java.smartcardio/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.smartcardio/LICENSE +open-fin-al/resources/jre-mac/legal/java.smartcardio/pcsclite.md +open-fin-al/resources/jre-mac/legal/java.sql/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.sql/LICENSE +open-fin-al/resources/jre-mac/legal/java.sql.rowset/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.sql.rowset/LICENSE +open-fin-al/resources/jre-mac/legal/java.transaction.xa/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.transaction.xa/LICENSE +open-fin-al/resources/jre-mac/legal/java.xml/bcel.md +open-fin-al/resources/jre-mac/legal/java.xml/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.xml/dom.md +open-fin-al/resources/jre-mac/legal/java.xml/jcup.md +open-fin-al/resources/jre-mac/legal/java.xml/LICENSE +open-fin-al/resources/jre-mac/legal/java.xml/schema10part1.md +open-fin-al/resources/jre-mac/legal/java.xml/schema10part2.md +open-fin-al/resources/jre-mac/legal/java.xml/xalan.md +open-fin-al/resources/jre-mac/legal/java.xml/xerces.md +open-fin-al/resources/jre-mac/legal/java.xml/xhtml10.md +open-fin-al/resources/jre-mac/legal/java.xml/xhtml10schema.md +open-fin-al/resources/jre-mac/legal/java.xml/xhtml11.md +open-fin-al/resources/jre-mac/legal/java.xml/xhtml11schema.md +open-fin-al/resources/jre-mac/legal/java.xml/xmlspec.md +open-fin-al/resources/jre-mac/legal/java.xml/xmlxsd.md +open-fin-al/resources/jre-mac/legal/java.xml.crypto/COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.xml.crypto/LICENSE +open-fin-al/resources/jre-mac/legal/java.xml.crypto/santuario.md +open-fin-al/resources/jre-mac/legal/jdk.accessibility/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.accessibility/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.attach/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.attach/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.charsets/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.charsets/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.compiler/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.compiler/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/pkcs11cryptotoken.md +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/pkcs11wrapper.md +open-fin-al/resources/jre-mac/legal/jdk.crypto.ec/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.crypto.ec/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.dynalink/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.dynalink/dynalink.md +open-fin-al/resources/jre-mac/legal/jdk.dynalink/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.editpad/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.editpad/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler.management/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler.management/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.hotspot.agent/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.hotspot.agent/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.httpserver/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.httpserver/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.incubator.vector/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.incubator.vector/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.ed/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.ed/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.jvmstat/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.jvmstat/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.le/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.le/jline.md +open-fin-al/resources/jre-mac/legal/jdk.internal.le/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.md/commonmark.md +open-fin-al/resources/jre-mac/legal/jdk.internal.md/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.md/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/jopt-simple.md +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.vm.ci/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.vm.ci/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jartool/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jartool/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.javadoc/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.javadoc/dejavufonts.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/highlightjs.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/jquery.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/jqueryUI.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jcmd/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jcmd/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jconsole/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jconsole/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdeps/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdeps/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdi/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdi/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdwp.agent/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdwp.agent/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jfr/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jfr/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jlink/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jlink/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jpackage/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jpackage/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jshell/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jshell/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jsobject/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jsobject/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jstatd/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jstatd/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.localedata/cldr.md +open-fin-al/resources/jre-mac/legal/jdk.localedata/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.localedata/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.localedata/thaidict.md +open-fin-al/resources/jre-mac/legal/jdk.management/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.management.agent/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management.agent/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.management.jfr/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management.jfr/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.naming.dns/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.naming.dns/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.naming.rmi/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.naming.rmi/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.net/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.net/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.nio.mapmode/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.nio.mapmode/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.sctp/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.sctp/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.security.auth/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.security.auth/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.security.jgss/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.security.jgss/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.unsupported/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.unsupported/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.unsupported.desktop/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.unsupported.desktop/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.xml.dom/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.xml.dom/LICENSE +open-fin-al/resources/jre-mac/legal/jdk.zipfs/COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.zipfs/LICENSE +open-fin-al/resources/jre-mac/lib/classlist +open-fin-al/resources/jre-mac/lib/ct.sym +open-fin-al/resources/jre-mac/lib/fontconfig.bfc +open-fin-al/resources/jre-mac/lib/fontconfig.properties.src +open-fin-al/resources/jre-mac/lib/jrt-fs.jar +open-fin-al/resources/jre-mac/lib/jspawnhelper +open-fin-al/resources/jre-mac/lib/jvm.cfg +open-fin-al/resources/jre-mac/lib/libattach.dylib +open-fin-al/resources/jre-mac/lib/libawt_lwawt.dylib +open-fin-al/resources/jre-mac/lib/libawt.dylib +open-fin-al/resources/jre-mac/lib/libdt_socket.dylib +open-fin-al/resources/jre-mac/lib/libextnet.dylib +open-fin-al/resources/jre-mac/lib/libfontmanager.dylib +open-fin-al/resources/jre-mac/lib/libfreetype.dylib +open-fin-al/resources/jre-mac/lib/libinstrument.dylib +open-fin-al/resources/jre-mac/lib/libj2gss.dylib +open-fin-al/resources/jre-mac/lib/libj2pcsc.dylib +open-fin-al/resources/jre-mac/lib/libj2pkcs11.dylib +open-fin-al/resources/jre-mac/lib/libjaas.dylib +open-fin-al/resources/jre-mac/lib/libjava.dylib +open-fin-al/resources/jre-mac/lib/libjavajpeg.dylib +open-fin-al/resources/jre-mac/lib/libjawt.dylib +open-fin-al/resources/jre-mac/lib/libjdwp.dylib +open-fin-al/resources/jre-mac/lib/libjimage.dylib +open-fin-al/resources/jre-mac/lib/libjli.dylib +open-fin-al/resources/jre-mac/lib/libjsig.dylib +open-fin-al/resources/jre-mac/lib/libjsound.dylib +open-fin-al/resources/jre-mac/lib/liblcms.dylib +open-fin-al/resources/jre-mac/lib/libmanagement_agent.dylib +open-fin-al/resources/jre-mac/lib/libmanagement_ext.dylib +open-fin-al/resources/jre-mac/lib/libmanagement.dylib +open-fin-al/resources/jre-mac/lib/libmlib_image.dylib +open-fin-al/resources/jre-mac/lib/libnet.dylib +open-fin-al/resources/jre-mac/lib/libnio.dylib +open-fin-al/resources/jre-mac/lib/libosx.dylib +open-fin-al/resources/jre-mac/lib/libosxapp.dylib +open-fin-al/resources/jre-mac/lib/libosxkrb5.dylib +open-fin-al/resources/jre-mac/lib/libosxsecurity.dylib +open-fin-al/resources/jre-mac/lib/libosxui.dylib +open-fin-al/resources/jre-mac/lib/libprefs.dylib +open-fin-al/resources/jre-mac/lib/librmi.dylib +open-fin-al/resources/jre-mac/lib/libsaproc.dylib +open-fin-al/resources/jre-mac/lib/libsleef.dylib +open-fin-al/resources/jre-mac/lib/libsplashscreen.dylib +open-fin-al/resources/jre-mac/lib/libsyslookup.dylib +open-fin-al/resources/jre-mac/lib/libverify.dylib +open-fin-al/resources/jre-mac/lib/libzip.dylib +open-fin-al/resources/jre-mac/lib/modules +open-fin-al/resources/jre-mac/lib/psfont.properties.ja +open-fin-al/resources/jre-mac/lib/psfontj2d.properties +open-fin-al/resources/jre-mac/lib/shaders.metallib +open-fin-al/resources/jre-mac/lib/src.zip +open-fin-al/resources/jre-mac/lib/tzdb.dat +open-fin-al/resources/jre-mac/lib/jfr/default.jfc +open-fin-al/resources/jre-mac/lib/jfr/profile.jfc +open-fin-al/resources/jre-mac/lib/security/blocked.certs +open-fin-al/resources/jre-mac/lib/security/cacerts +open-fin-al/resources/jre-mac/lib/security/public_suffix_list.dat +open-fin-al/resources/jre-mac/lib/server/classes_coh.jsa +open-fin-al/resources/jre-mac/lib/server/classes_nocoops_coh.jsa +open-fin-al/resources/jre-mac/lib/server/classes_nocoops.jsa +open-fin-al/resources/jre-mac/lib/server/classes.jsa +open-fin-al/resources/jre-mac/lib/server/libjsig.dylib +open-fin-al/resources/jre-mac/lib/server/libjvm.dylib +open-fin-al/resources/jre-mac/man/man1/jar.1 +open-fin-al/resources/jre-mac/man/man1/jarsigner.1 +open-fin-al/resources/jre-mac/man/man1/java.1 +open-fin-al/resources/jre-mac/man/man1/javac.1 +open-fin-al/resources/jre-mac/man/man1/javadoc.1 +open-fin-al/resources/jre-mac/man/man1/javap.1 +open-fin-al/resources/jre-mac/man/man1/jcmd.1 +open-fin-al/resources/jre-mac/man/man1/jconsole.1 +open-fin-al/resources/jre-mac/man/man1/jdb.1 +open-fin-al/resources/jre-mac/man/man1/jdeprscan.1 +open-fin-al/resources/jre-mac/man/man1/jdeps.1 +open-fin-al/resources/jre-mac/man/man1/jfr.1 +open-fin-al/resources/jre-mac/man/man1/jhsdb.1 +open-fin-al/resources/jre-mac/man/man1/jinfo.1 +open-fin-al/resources/jre-mac/man/man1/jlink.1 +open-fin-al/resources/jre-mac/man/man1/jmap.1 +open-fin-al/resources/jre-mac/man/man1/jmod.1 +open-fin-al/resources/jre-mac/man/man1/jnativescan.1 +open-fin-al/resources/jre-mac/man/man1/jpackage.1 +open-fin-al/resources/jre-mac/man/man1/jps.1 +open-fin-al/resources/jre-mac/man/man1/jrunscript.1 +open-fin-al/resources/jre-mac/man/man1/jshell.1 +open-fin-al/resources/jre-mac/man/man1/jstack.1 +open-fin-al/resources/jre-mac/man/man1/jstat.1 +open-fin-al/resources/jre-mac/man/man1/jstatd.1 +open-fin-al/resources/jre-mac/man/man1/jwebserver.1 +open-fin-al/resources/jre-mac/man/man1/keytool.1 +open-fin-al/resources/jre-mac/man/man1/rmiregistry.1 +open-fin-al/resources/jre-mac/man/man1/serialver.1 +open-fin-al/resources/neo4j-mac/LICENSE.txt +open-fin-al/resources/neo4j-mac/LICENSES.txt +open-fin-al/resources/neo4j-mac/NOTICE.txt +open-fin-al/resources/neo4j-mac/packaging_info +open-fin-al/resources/neo4j-mac/README.txt +open-fin-al/resources/neo4j-mac/UPGRADE.txt +open-fin-al/resources/neo4j-mac/bin/cypher-shell +open-fin-al/resources/neo4j-mac/bin/neo4j +open-fin-al/resources/neo4j-mac/bin/neo4j-admin +open-fin-al/resources/neo4j-mac/bin/completion/neo4j_completion +open-fin-al/resources/neo4j-mac/bin/completion/neo4j-admin_completion +open-fin-al/resources/neo4j-mac/conf/neo4j-admin.conf +open-fin-al/resources/neo4j-mac/conf/neo4j.conf +open-fin-al/resources/neo4j-mac/conf/server-logs.xml +open-fin-al/resources/neo4j-mac/conf/user-logs.xml +open-fin-al/resources/neo4j-mac/labs/apoc-2026.01.4-core.jar +open-fin-al/resources/neo4j-mac/labs/LICENSE +open-fin-al/resources/neo4j-mac/labs/README.txt +open-fin-al/resources/neo4j-mac/lib/annotations-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/antlr4-runtime-4.13.2.jar +open-fin-al/resources/neo4j-mac/lib/argparse4j-0.9.0.jar +open-fin-al/resources/neo4j-mac/lib/arrow-bom-2026.01.4.pom +open-fin-al/resources/neo4j-mac/lib/arrow-format-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/arrow-memory-core-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/arrow-memory-netty-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/arrow-memory-netty-buffer-patch-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/arrow-vector-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/asm-9.9.jar +open-fin-al/resources/neo4j-mac/lib/asm-analysis-9.9.jar +open-fin-al/resources/neo4j-mac/lib/asm-tree-9.9.jar +open-fin-al/resources/neo4j-mac/lib/asm-util-9.9.jar +open-fin-al/resources/neo4j-mac/lib/caffeine-3.2.3.jar +open-fin-al/resources/neo4j-mac/lib/commons-codec-1.20.0.jar +open-fin-al/resources/neo4j-mac/lib/commons-compress-1.28.0.jar +open-fin-al/resources/neo4j-mac/lib/commons-configuration2-2.13.0.jar +open-fin-al/resources/neo4j-mac/lib/commons-io-2.21.0.jar +open-fin-al/resources/neo4j-mac/lib/commons-lang3-3.20.0.jar +open-fin-al/resources/neo4j-mac/lib/commons-logging-1.3.5.jar +open-fin-al/resources/neo4j-mac/lib/commons-pool-1.6.jar +open-fin-al/resources/neo4j-mac/lib/commons-text-1.15.0.jar +open-fin-al/resources/neo4j-mac/lib/cypher-antlr-ast-common-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-antlr-common-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-ast-common-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-common-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-factory-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-preparser-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-shell-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-antlr-parser-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-ast-factory-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-literal-interpreter-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-parser-listener-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-antlr-parser-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-ast-factory-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-parser-listener-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/eclipse-collections-11.1.0.jar +open-fin-al/resources/neo4j-mac/lib/eclipse-collections-api-11.1.0.jar +open-fin-al/resources/neo4j-mac/lib/failureaccess-1.0.3.jar +open-fin-al/resources/neo4j-mac/lib/FastInfoset-1.2.16.jar +open-fin-al/resources/neo4j-mac/lib/flatbuffers-java-25.2.10.jar +open-fin-al/resources/neo4j-mac/lib/flight-core-18.3.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-api-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-context-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-core-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-netty-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-protobuf-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-protobuf-lite-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-stub-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/grpc-util-1.77.0.jar +open-fin-al/resources/neo4j-mac/lib/gson-2.11.0.jar +open-fin-al/resources/neo4j-mac/lib/guava-33.5.0-jre.jar +open-fin-al/resources/neo4j-mac/lib/hk2-api-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/hk2-locator-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/hk2-utils-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/ipaddress-5.5.1.jar +open-fin-al/resources/neo4j-mac/lib/istack-commons-runtime-3.0.8.jar +open-fin-al/resources/neo4j-mac/lib/jackson-annotations-2.20.jar +open-fin-al/resources/neo4j-mac/lib/jackson-core-2.20.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-databind-2.20.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-datatype-jsr310-2.18.3.jar +open-fin-al/resources/neo4j-mac/lib/jackson-jaxrs-base-2.20.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-jaxrs-json-provider-2.20.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-module-jaxb-annotations-2.20.1.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.activation-api-1.2.2.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.annotation-api-1.3.5.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.inject-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.validation-api-2.0.2.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.ws.rs-api-2.1.6.jar +open-fin-al/resources/neo4j-mac/lib/jakarta.xml.bind-api-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/jansi-2.4.0.jar +open-fin-al/resources/neo4j-mac/lib/java-jwt-4.5.0.jar +open-fin-al/resources/neo4j-mac/lib/javassist-3.30.2-GA.jar +open-fin-al/resources/neo4j-mac/lib/javax.annotation-api-1.3.2.jar +open-fin-al/resources/neo4j-mac/lib/jaxb-api-2.2.12.jar +open-fin-al/resources/neo4j-mac/lib/jaxb-runtime-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/jctools-core-4.0.5.jar +open-fin-al/resources/neo4j-mac/lib/jersey-client-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jersey-common-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jersey-container-servlet-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jersey-container-servlet-core-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jersey-hk2-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jersey-server-2.46.jar +open-fin-al/resources/neo4j-mac/lib/jettison-1.5.4.jar +open-fin-al/resources/neo4j-mac/lib/jetty-alpn-java-server-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-alpn-server-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-nested-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-security-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-servlet-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-webapp-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-common-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-hpack-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-server-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-io-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-security-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-server-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-servlet-api-4.0.6.jar +open-fin-al/resources/neo4j-mac/lib/jetty-session-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-util-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jetty-xml-12.0.25.jar +open-fin-al/resources/neo4j-mac/lib/jline-reader-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/jline-terminal-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/jline-terminal-jansi-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/jna-5.18.1.jar +open-fin-al/resources/neo4j-mac/lib/jPowerShell-3.0.jar +open-fin-al/resources/neo4j-mac/lib/jProcesses-1.6.5.jar +open-fin-al/resources/neo4j-mac/lib/jsr305-3.0.2.jar +open-fin-al/resources/neo4j-mac/lib/jts-core-1.20.0.jar +open-fin-al/resources/neo4j-mac/lib/kiama_2.13-2.5.1.jar +open-fin-al/resources/neo4j-mac/lib/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar +open-fin-al/resources/neo4j-mac/lib/log4j-api-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/log4j-core-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/log4j-layout-template-json-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/lucene-analysis-common-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/lucene-backward-codecs-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/lucene-core-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/lucene-queryparser-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/lucene9-shaded-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/magnolia_2.13-1.1.8.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-ast-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-connection-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-connection-netty-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-connection-pooled-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-connection-routed-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bootcheck-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-browser-ce-2025.8.0.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-capabilities-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cloud-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-codegen-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-collections-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-command-line-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-common-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-concurrent-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-configuration-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-consistency-check-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-csv-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-cache-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-config-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-dsl-2025.2.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-expression-evaluator-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-interpreted-runtime-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-ir-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-logical-plans-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-macros-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-physical-planning-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-planner-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-planner-spi-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-rendering-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-runtime-util-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-slotted-runtime-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-data-collector-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-dbms-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-diagnostics-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-exceptions-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-expressions-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-fabric-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-fleet-management-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-front-end-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-gql-status-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-graph-algo-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-graphdb-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-id-generator-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-tool-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-util-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-index-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-indexcommands-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-internal-notifications-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-io-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-java-driver-6.0.2.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-jdbc-value-mapper-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-kernel-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-kernel-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-layout-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-lock-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-logging-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-lucene-index-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-monitoring-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-native-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-notifications-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-procedure-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-procedure-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-push-to-cloud-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-query-router-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-record-storage-engine-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-resource-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-rewriting-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-schema-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-security-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-server-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-slf4j-provider-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-spatial-index-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-ssl-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-storage-engine-util-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-token-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-udc-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-unsafe-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-util-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-values-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-wal-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/netty-buffer-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-base-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-compression-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-http-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-http2-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-socks-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-common-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-handler-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-handler-proxy-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-resolver-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative-classes-2.0.74.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-classes-epoll-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-classes-kqueue-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-epoll-4.2.9.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-epoll-4.2.9.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-kqueue-4.2.9.Final-osx-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-kqueue-4.2.9.Final-osx-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-unix-common-4.2.9.Final.jar +open-fin-al/resources/neo4j-mac/lib/parquet-column-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-common-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-encoding-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-floor-1.59.jar +open-fin-al/resources/neo4j-mac/lib/parquet-format-structures-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-hadoop-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-jackson-1.16.0.jar +open-fin-al/resources/neo4j-mac/lib/perfmark-api-0.27.0.jar +open-fin-al/resources/neo4j-mac/lib/picocli-4.7.7.jar +open-fin-al/resources/neo4j-mac/lib/proto-google-common-protos-2.59.2.jar +open-fin-al/resources/neo4j-mac/lib/protobuf-java-4.33.2.jar +open-fin-al/resources/neo4j-mac/lib/protobuf-java-util-4.33.2.jar +open-fin-al/resources/neo4j-mac/lib/reactive-streams-1.0.4.jar +open-fin-al/resources/neo4j-mac/lib/reactor-core-3.7.11.jar +open-fin-al/resources/neo4j-mac/lib/scala-collection-contrib_2.13-0.3.0.jar +open-fin-al/resources/neo4j-mac/lib/scala-library-2.13.17.jar +open-fin-al/resources/neo4j-mac/lib/scala-reflect-2.13.17.jar +open-fin-al/resources/neo4j-mac/lib/server-api-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/shiro-cache-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-config-core-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-core-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-cipher-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-core-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-hash-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-event-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-hashes-argon2-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-hashes-bcrypt-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/shiro-lang-2.0.6.jar +open-fin-al/resources/neo4j-mac/lib/slf4j-api-2.0.17.jar +open-fin-al/resources/neo4j-mac/lib/snappy-java-1.1.10.7.jar +open-fin-al/resources/neo4j-mac/lib/stax-ex-1.8.1.jar +open-fin-al/resources/neo4j-mac/lib/txw2-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/WMI4Java-1.6.3.jar +open-fin-al/resources/neo4j-mac/lib/zstd-jni-1.5.7-6.jar +open-fin-al/resources/neo4j-mac/lib/zstd-proxy-2026.01.4.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.74.Final-linux-aarch_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.74.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.74.Final-linux-x86_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.74.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.74.Final.jar +open-fin-al/resources/neo4j-mac/plugins/README.txt +open-fin-al/resources/neo4j-mac/products/neo4j-fleet-management-plugin-1.1.1-v2025.jar +open-fin-al/resources/README.md +open-fin-al/._.webpack +open-fin-al/resources/._jre-mac +open-fin-al/resources/._neo4j-mac +open-fin-al/resources/jre-mac/._bin +open-fin-al/resources/jre-mac/._conf +open-fin-al/resources/jre-mac/._include +open-fin-al/resources/jre-mac/._jmods +open-fin-al/resources/jre-mac/._legal +open-fin-al/resources/jre-mac/._lib +open-fin-al/resources/jre-mac/._LICENSE +open-fin-al/resources/jre-mac/._man +open-fin-al/resources/jre-mac/._README +open-fin-al/resources/jre-mac/._release +open-fin-al/resources/jre-mac/bin/._jar +open-fin-al/resources/jre-mac/bin/._jarsigner +open-fin-al/resources/jre-mac/bin/._java +open-fin-al/resources/jre-mac/bin/._javac +open-fin-al/resources/jre-mac/bin/._javadoc +open-fin-al/resources/jre-mac/bin/._javap +open-fin-al/resources/jre-mac/bin/._jcmd +open-fin-al/resources/jre-mac/bin/._jconsole +open-fin-al/resources/jre-mac/bin/._jdb +open-fin-al/resources/jre-mac/bin/._jdeprscan +open-fin-al/resources/jre-mac/bin/._jdeps +open-fin-al/resources/jre-mac/bin/._jfr +open-fin-al/resources/jre-mac/bin/._jhsdb +open-fin-al/resources/jre-mac/bin/._jimage +open-fin-al/resources/jre-mac/bin/._jinfo +open-fin-al/resources/jre-mac/bin/._jlink +open-fin-al/resources/jre-mac/bin/._jmap +open-fin-al/resources/jre-mac/bin/._jmod +open-fin-al/resources/jre-mac/bin/._jnativescan +open-fin-al/resources/jre-mac/bin/._jpackage +open-fin-al/resources/jre-mac/bin/._jps +open-fin-al/resources/jre-mac/bin/._jshell +open-fin-al/resources/jre-mac/bin/._jstack +open-fin-al/resources/jre-mac/bin/._jstat +open-fin-al/resources/jre-mac/bin/._jstatd +open-fin-al/resources/jre-mac/bin/._jwebserver +open-fin-al/resources/jre-mac/bin/._keytool +open-fin-al/resources/jre-mac/bin/._rmiregistry +open-fin-al/resources/jre-mac/bin/._serialver +open-fin-al/resources/jre-mac/conf/._jaxp-strict.properties.template +open-fin-al/resources/jre-mac/conf/._jaxp.properties +open-fin-al/resources/jre-mac/conf/._logging.properties +open-fin-al/resources/jre-mac/conf/._management +open-fin-al/resources/jre-mac/conf/._net.properties +open-fin-al/resources/jre-mac/conf/._security +open-fin-al/resources/jre-mac/conf/._sound.properties +open-fin-al/resources/jre-mac/conf/management/._jmxremote.access +open-fin-al/resources/jre-mac/conf/management/._jmxremote.password.template +open-fin-al/resources/jre-mac/conf/management/._management.properties +open-fin-al/resources/jre-mac/conf/security/._java.security +open-fin-al/resources/jre-mac/conf/security/._policy +open-fin-al/resources/jre-mac/conf/security/policy/._limited +open-fin-al/resources/jre-mac/conf/security/policy/._README.txt +open-fin-al/resources/jre-mac/conf/security/policy/._unlimited +open-fin-al/resources/jre-mac/conf/security/policy/limited/._default_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/limited/._default_US_export.policy +open-fin-al/resources/jre-mac/conf/security/policy/limited/._exempt_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/unlimited/._default_local.policy +open-fin-al/resources/jre-mac/conf/security/policy/unlimited/._default_US_export.policy +open-fin-al/resources/jre-mac/include/._classfile_constants.h +open-fin-al/resources/jre-mac/include/._darwin +open-fin-al/resources/jre-mac/include/._jawt.h +open-fin-al/resources/jre-mac/include/._jdwpTransport.h +open-fin-al/resources/jre-mac/include/._jni.h +open-fin-al/resources/jre-mac/include/._jvmti.h +open-fin-al/resources/jre-mac/include/._jvmticmlr.h +open-fin-al/resources/jre-mac/include/darwin/._jawt_md.h +open-fin-al/resources/jre-mac/include/darwin/._jni_md.h +open-fin-al/resources/jre-mac/jmods/._java.base.jmod +open-fin-al/resources/jre-mac/jmods/._java.compiler.jmod +open-fin-al/resources/jre-mac/jmods/._java.datatransfer.jmod +open-fin-al/resources/jre-mac/jmods/._java.desktop.jmod +open-fin-al/resources/jre-mac/jmods/._java.instrument.jmod +open-fin-al/resources/jre-mac/jmods/._java.logging.jmod +open-fin-al/resources/jre-mac/jmods/._java.management.jmod +open-fin-al/resources/jre-mac/jmods/._java.management.rmi.jmod +open-fin-al/resources/jre-mac/jmods/._java.naming.jmod +open-fin-al/resources/jre-mac/jmods/._java.net.http.jmod +open-fin-al/resources/jre-mac/jmods/._java.prefs.jmod +open-fin-al/resources/jre-mac/jmods/._java.rmi.jmod +open-fin-al/resources/jre-mac/jmods/._java.scripting.jmod +open-fin-al/resources/jre-mac/jmods/._java.se.jmod +open-fin-al/resources/jre-mac/jmods/._java.security.jgss.jmod +open-fin-al/resources/jre-mac/jmods/._java.security.sasl.jmod +open-fin-al/resources/jre-mac/jmods/._java.smartcardio.jmod +open-fin-al/resources/jre-mac/jmods/._java.sql.jmod +open-fin-al/resources/jre-mac/jmods/._java.sql.rowset.jmod +open-fin-al/resources/jre-mac/jmods/._java.transaction.xa.jmod +open-fin-al/resources/jre-mac/jmods/._java.xml.crypto.jmod +open-fin-al/resources/jre-mac/jmods/._java.xml.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.accessibility.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.attach.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.charsets.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.compiler.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.crypto.cryptoki.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.crypto.ec.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.dynalink.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.editpad.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.graal.compiler.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.graal.compiler.management.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.hotspot.agent.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.httpserver.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.incubator.vector.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.ed.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.jvmstat.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.le.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.md.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.opt.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.internal.vm.ci.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jartool.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.javadoc.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jcmd.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jconsole.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jdeps.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jdi.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jdwp.agent.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jfr.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jlink.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jpackage.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jshell.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.jstatd.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.localedata.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.management.agent.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.management.jfr.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.management.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.naming.dns.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.naming.rmi.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.net.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.nio.mapmode.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.sctp.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.security.auth.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.security.jgss.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.unsupported.desktop.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.unsupported.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.xml.dom.jmod +open-fin-al/resources/jre-mac/jmods/._jdk.zipfs.jmod +open-fin-al/resources/jre-mac/legal/._java.base +open-fin-al/resources/jre-mac/legal/._java.compiler +open-fin-al/resources/jre-mac/legal/._java.datatransfer +open-fin-al/resources/jre-mac/legal/._java.desktop +open-fin-al/resources/jre-mac/legal/._java.instrument +open-fin-al/resources/jre-mac/legal/._java.logging +open-fin-al/resources/jre-mac/legal/._java.management +open-fin-al/resources/jre-mac/legal/._java.management.rmi +open-fin-al/resources/jre-mac/legal/._java.naming +open-fin-al/resources/jre-mac/legal/._java.net.http +open-fin-al/resources/jre-mac/legal/._java.prefs +open-fin-al/resources/jre-mac/legal/._java.rmi +open-fin-al/resources/jre-mac/legal/._java.scripting +open-fin-al/resources/jre-mac/legal/._java.se +open-fin-al/resources/jre-mac/legal/._java.security.jgss +open-fin-al/resources/jre-mac/legal/._java.security.sasl +open-fin-al/resources/jre-mac/legal/._java.smartcardio +open-fin-al/resources/jre-mac/legal/._java.sql +open-fin-al/resources/jre-mac/legal/._java.sql.rowset +open-fin-al/resources/jre-mac/legal/._java.transaction.xa +open-fin-al/resources/jre-mac/legal/._java.xml +open-fin-al/resources/jre-mac/legal/._java.xml.crypto +open-fin-al/resources/jre-mac/legal/._jdk.accessibility +open-fin-al/resources/jre-mac/legal/._jdk.attach +open-fin-al/resources/jre-mac/legal/._jdk.charsets +open-fin-al/resources/jre-mac/legal/._jdk.compiler +open-fin-al/resources/jre-mac/legal/._jdk.crypto.cryptoki +open-fin-al/resources/jre-mac/legal/._jdk.crypto.ec +open-fin-al/resources/jre-mac/legal/._jdk.dynalink +open-fin-al/resources/jre-mac/legal/._jdk.editpad +open-fin-al/resources/jre-mac/legal/._jdk.graal.compiler +open-fin-al/resources/jre-mac/legal/._jdk.graal.compiler.management +open-fin-al/resources/jre-mac/legal/._jdk.hotspot.agent +open-fin-al/resources/jre-mac/legal/._jdk.httpserver +open-fin-al/resources/jre-mac/legal/._jdk.incubator.vector +open-fin-al/resources/jre-mac/legal/._jdk.internal.ed +open-fin-al/resources/jre-mac/legal/._jdk.internal.jvmstat +open-fin-al/resources/jre-mac/legal/._jdk.internal.le +open-fin-al/resources/jre-mac/legal/._jdk.internal.md +open-fin-al/resources/jre-mac/legal/._jdk.internal.opt +open-fin-al/resources/jre-mac/legal/._jdk.internal.vm.ci +open-fin-al/resources/jre-mac/legal/._jdk.jartool +open-fin-al/resources/jre-mac/legal/._jdk.javadoc +open-fin-al/resources/jre-mac/legal/._jdk.jcmd +open-fin-al/resources/jre-mac/legal/._jdk.jconsole +open-fin-al/resources/jre-mac/legal/._jdk.jdeps +open-fin-al/resources/jre-mac/legal/._jdk.jdi +open-fin-al/resources/jre-mac/legal/._jdk.jdwp.agent +open-fin-al/resources/jre-mac/legal/._jdk.jfr +open-fin-al/resources/jre-mac/legal/._jdk.jlink +open-fin-al/resources/jre-mac/legal/._jdk.jpackage +open-fin-al/resources/jre-mac/legal/._jdk.jshell +open-fin-al/resources/jre-mac/legal/._jdk.jstatd +open-fin-al/resources/jre-mac/legal/._jdk.localedata +open-fin-al/resources/jre-mac/legal/._jdk.management +open-fin-al/resources/jre-mac/legal/._jdk.management.agent +open-fin-al/resources/jre-mac/legal/._jdk.management.jfr +open-fin-al/resources/jre-mac/legal/._jdk.naming.dns +open-fin-al/resources/jre-mac/legal/._jdk.naming.rmi +open-fin-al/resources/jre-mac/legal/._jdk.net +open-fin-al/resources/jre-mac/legal/._jdk.nio.mapmode +open-fin-al/resources/jre-mac/legal/._jdk.sctp +open-fin-al/resources/jre-mac/legal/._jdk.security.auth +open-fin-al/resources/jre-mac/legal/._jdk.security.jgss +open-fin-al/resources/jre-mac/legal/._jdk.unsupported +open-fin-al/resources/jre-mac/legal/._jdk.unsupported.desktop +open-fin-al/resources/jre-mac/legal/._jdk.xml.dom +open-fin-al/resources/jre-mac/legal/._jdk.zipfs +open-fin-al/resources/jre-mac/legal/java.base/._c-libutl.md +open-fin-al/resources/jre-mac/legal/java.base/._cldr.md +open-fin-al/resources/jre-mac/legal/java.base/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.base/._gcc.md +open-fin-al/resources/jre-mac/legal/java.base/._icu.md +open-fin-al/resources/jre-mac/legal/java.base/._LICENSE +open-fin-al/resources/jre-mac/legal/java.base/._public_suffix.md +open-fin-al/resources/jre-mac/legal/java.base/._siphash.md +open-fin-al/resources/jre-mac/legal/java.base/._unicode.md +open-fin-al/resources/jre-mac/legal/java.base/._zlib.md +open-fin-al/resources/jre-mac/legal/java.base/gcc.md +open-fin-al/resources/jre-mac/legal/java.compiler/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.compiler/._LICENSE +open-fin-al/resources/jre-mac/legal/java.datatransfer/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.datatransfer/._LICENSE +open-fin-al/resources/jre-mac/legal/java.desktop/._colorimaging.md +open-fin-al/resources/jre-mac/legal/java.desktop/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.desktop/._freetype.md +open-fin-al/resources/jre-mac/legal/java.desktop/._giflib.md +open-fin-al/resources/jre-mac/legal/java.desktop/._harfbuzz.md +open-fin-al/resources/jre-mac/legal/java.desktop/._jpeg.md +open-fin-al/resources/jre-mac/legal/java.desktop/._lcms.md +open-fin-al/resources/jre-mac/legal/java.desktop/._libpng.md +open-fin-al/resources/jre-mac/legal/java.desktop/._LICENSE +open-fin-al/resources/jre-mac/legal/java.desktop/._mesa3d.md +open-fin-al/resources/jre-mac/legal/java.desktop/._pipewire.md +open-fin-al/resources/jre-mac/legal/java.desktop/._xwd.md +open-fin-al/resources/jre-mac/legal/java.instrument/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.instrument/._LICENSE +open-fin-al/resources/jre-mac/legal/java.logging/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.logging/._LICENSE +open-fin-al/resources/jre-mac/legal/java.management/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.management/._LICENSE +open-fin-al/resources/jre-mac/legal/java.management.rmi/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.management.rmi/._LICENSE +open-fin-al/resources/jre-mac/legal/java.naming/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.naming/._LICENSE +open-fin-al/resources/jre-mac/legal/java.net.http/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.net.http/._LICENSE +open-fin-al/resources/jre-mac/legal/java.prefs/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.prefs/._LICENSE +open-fin-al/resources/jre-mac/legal/java.rmi/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.rmi/._LICENSE +open-fin-al/resources/jre-mac/legal/java.scripting/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.scripting/._LICENSE +open-fin-al/resources/jre-mac/legal/java.se/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.se/._LICENSE +open-fin-al/resources/jre-mac/legal/java.security.jgss/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.security.jgss/._LICENSE +open-fin-al/resources/jre-mac/legal/java.security.sasl/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.security.sasl/._LICENSE +open-fin-al/resources/jre-mac/legal/java.smartcardio/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.smartcardio/._LICENSE +open-fin-al/resources/jre-mac/legal/java.smartcardio/._pcsclite.md +open-fin-al/resources/jre-mac/legal/java.sql/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.sql/._LICENSE +open-fin-al/resources/jre-mac/legal/java.sql.rowset/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.sql.rowset/._LICENSE +open-fin-al/resources/jre-mac/legal/java.transaction.xa/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.transaction.xa/._LICENSE +open-fin-al/resources/jre-mac/legal/java.xml/._bcel.md +open-fin-al/resources/jre-mac/legal/java.xml/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.xml/._dom.md +open-fin-al/resources/jre-mac/legal/java.xml/._jcup.md +open-fin-al/resources/jre-mac/legal/java.xml/._LICENSE +open-fin-al/resources/jre-mac/legal/java.xml/._schema10part1.md +open-fin-al/resources/jre-mac/legal/java.xml/._schema10part2.md +open-fin-al/resources/jre-mac/legal/java.xml/._xalan.md +open-fin-al/resources/jre-mac/legal/java.xml/._xerces.md +open-fin-al/resources/jre-mac/legal/java.xml/._xhtml10.md +open-fin-al/resources/jre-mac/legal/java.xml/._xhtml10schema.md +open-fin-al/resources/jre-mac/legal/java.xml/._xhtml11.md +open-fin-al/resources/jre-mac/legal/java.xml/._xhtml11schema.md +open-fin-al/resources/jre-mac/legal/java.xml/._xmlspec.md +open-fin-al/resources/jre-mac/legal/java.xml/._xmlxsd.md +open-fin-al/resources/jre-mac/legal/java.xml.crypto/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/java.xml.crypto/._LICENSE +open-fin-al/resources/jre-mac/legal/java.xml.crypto/._santuario.md +open-fin-al/resources/jre-mac/legal/jdk.accessibility/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.accessibility/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.attach/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.attach/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.charsets/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.charsets/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.compiler/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.compiler/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/._pkcs11cryptotoken.md +open-fin-al/resources/jre-mac/legal/jdk.crypto.cryptoki/._pkcs11wrapper.md +open-fin-al/resources/jre-mac/legal/jdk.crypto.ec/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.crypto.ec/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.dynalink/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.dynalink/._dynalink.md +open-fin-al/resources/jre-mac/legal/jdk.dynalink/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.editpad/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.editpad/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler.management/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.graal.compiler.management/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.hotspot.agent/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.hotspot.agent/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.httpserver/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.httpserver/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.incubator.vector/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.incubator.vector/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.ed/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.ed/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.jvmstat/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.jvmstat/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.le/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.le/._jline.md +open-fin-al/resources/jre-mac/legal/jdk.internal.le/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.md/._commonmark.md +open-fin-al/resources/jre-mac/legal/jdk.internal.md/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.md/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/._jopt-simple.md +open-fin-al/resources/jre-mac/legal/jdk.internal.opt/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.internal.vm.ci/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.internal.vm.ci/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jartool/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jartool/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._dejavufonts.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._highlightjs.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._jquery.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._jqueryUI.md +open-fin-al/resources/jre-mac/legal/jdk.javadoc/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jcmd/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jcmd/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jconsole/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jconsole/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdeps/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdeps/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdi/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdi/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jdwp.agent/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jdwp.agent/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jfr/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jfr/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jlink/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jlink/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jpackage/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jpackage/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jshell/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jshell/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.jstatd/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.jstatd/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.localedata/._cldr.md +open-fin-al/resources/jre-mac/legal/jdk.localedata/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.localedata/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.localedata/._thaidict.md +open-fin-al/resources/jre-mac/legal/jdk.management/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.management.agent/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management.agent/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.management.jfr/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.management.jfr/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.naming.dns/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.naming.dns/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.naming.rmi/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.naming.rmi/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.net/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.net/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.nio.mapmode/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.nio.mapmode/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.sctp/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.sctp/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.security.auth/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.security.auth/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.security.jgss/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.security.jgss/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.unsupported/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.unsupported/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.unsupported.desktop/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.unsupported.desktop/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.xml.dom/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.xml.dom/._LICENSE +open-fin-al/resources/jre-mac/legal/jdk.zipfs/._COPYRIGHT +open-fin-al/resources/jre-mac/legal/jdk.zipfs/._LICENSE +open-fin-al/resources/jre-mac/lib/._classlist +open-fin-al/resources/jre-mac/lib/._ct.sym +open-fin-al/resources/jre-mac/lib/._fontconfig.bfc +open-fin-al/resources/jre-mac/lib/._fontconfig.properties.src +open-fin-al/resources/jre-mac/lib/._jfr +open-fin-al/resources/jre-mac/lib/._jrt-fs.jar +open-fin-al/resources/jre-mac/lib/._jspawnhelper +open-fin-al/resources/jre-mac/lib/._jvm.cfg +open-fin-al/resources/jre-mac/lib/._libattach.dylib +open-fin-al/resources/jre-mac/lib/._libawt_lwawt.dylib +open-fin-al/resources/jre-mac/lib/._libawt.dylib +open-fin-al/resources/jre-mac/lib/._libdt_socket.dylib +open-fin-al/resources/jre-mac/lib/._libextnet.dylib +open-fin-al/resources/jre-mac/lib/._libfontmanager.dylib +open-fin-al/resources/jre-mac/lib/._libfreetype.dylib +open-fin-al/resources/jre-mac/lib/._libinstrument.dylib +open-fin-al/resources/jre-mac/lib/._libj2gss.dylib +open-fin-al/resources/jre-mac/lib/._libj2pcsc.dylib +open-fin-al/resources/jre-mac/lib/._libj2pkcs11.dylib +open-fin-al/resources/jre-mac/lib/._libjaas.dylib +open-fin-al/resources/jre-mac/lib/._libjava.dylib +open-fin-al/resources/jre-mac/lib/._libjavajpeg.dylib +open-fin-al/resources/jre-mac/lib/._libjawt.dylib +open-fin-al/resources/jre-mac/lib/._libjdwp.dylib +open-fin-al/resources/jre-mac/lib/._libjimage.dylib +open-fin-al/resources/jre-mac/lib/._libjli.dylib +open-fin-al/resources/jre-mac/lib/._libjsig.dylib +open-fin-al/resources/jre-mac/lib/._libjsound.dylib +open-fin-al/resources/jre-mac/lib/._liblcms.dylib +open-fin-al/resources/jre-mac/lib/._libmanagement_agent.dylib +open-fin-al/resources/jre-mac/lib/._libmanagement_ext.dylib +open-fin-al/resources/jre-mac/lib/._libmanagement.dylib +open-fin-al/resources/jre-mac/lib/._libmlib_image.dylib +open-fin-al/resources/jre-mac/lib/._libnet.dylib +open-fin-al/resources/jre-mac/lib/._libnio.dylib +open-fin-al/resources/jre-mac/lib/._libosx.dylib +open-fin-al/resources/jre-mac/lib/._libosxapp.dylib +open-fin-al/resources/jre-mac/lib/._libosxkrb5.dylib +open-fin-al/resources/jre-mac/lib/._libosxsecurity.dylib +open-fin-al/resources/jre-mac/lib/._libosxui.dylib +open-fin-al/resources/jre-mac/lib/._libprefs.dylib +open-fin-al/resources/jre-mac/lib/._librmi.dylib +open-fin-al/resources/jre-mac/lib/._libsaproc.dylib +open-fin-al/resources/jre-mac/lib/._libsleef.dylib +open-fin-al/resources/jre-mac/lib/._libsplashscreen.dylib +open-fin-al/resources/jre-mac/lib/._libsyslookup.dylib +open-fin-al/resources/jre-mac/lib/._libverify.dylib +open-fin-al/resources/jre-mac/lib/._libzip.dylib +open-fin-al/resources/jre-mac/lib/._modules +open-fin-al/resources/jre-mac/lib/._psfont.properties.ja +open-fin-al/resources/jre-mac/lib/._psfontj2d.properties +open-fin-al/resources/jre-mac/lib/._security +open-fin-al/resources/jre-mac/lib/._server +open-fin-al/resources/jre-mac/lib/._shaders.metallib +open-fin-al/resources/jre-mac/lib/._src.zip +open-fin-al/resources/jre-mac/lib/._tzdb.dat +open-fin-al/resources/jre-mac/lib/jfr/._default.jfc +open-fin-al/resources/jre-mac/lib/jfr/._profile.jfc +open-fin-al/resources/jre-mac/lib/security/._blocked.certs +open-fin-al/resources/jre-mac/lib/security/._cacerts +open-fin-al/resources/jre-mac/lib/security/._public_suffix_list.dat +open-fin-al/resources/jre-mac/lib/server/._classes_coh.jsa +open-fin-al/resources/jre-mac/lib/server/._classes_nocoops_coh.jsa +open-fin-al/resources/jre-mac/lib/server/._classes_nocoops.jsa +open-fin-al/resources/jre-mac/lib/server/._classes.jsa +open-fin-al/resources/jre-mac/lib/server/._libjsig.dylib +open-fin-al/resources/jre-mac/lib/server/._libjvm.dylib +open-fin-al/resources/jre-mac/man/._man1 +open-fin-al/resources/jre-mac/man/man1/._jar.1 +open-fin-al/resources/jre-mac/man/man1/._jarsigner.1 +open-fin-al/resources/jre-mac/man/man1/._java.1 +open-fin-al/resources/jre-mac/man/man1/._javac.1 +open-fin-al/resources/jre-mac/man/man1/._javadoc.1 +open-fin-al/resources/jre-mac/man/man1/._javap.1 +open-fin-al/resources/jre-mac/man/man1/._jcmd.1 +open-fin-al/resources/jre-mac/man/man1/._jconsole.1 +open-fin-al/resources/jre-mac/man/man1/._jdb.1 +open-fin-al/resources/jre-mac/man/man1/._jdeprscan.1 +open-fin-al/resources/jre-mac/man/man1/._jdeps.1 +open-fin-al/resources/jre-mac/man/man1/._jfr.1 +open-fin-al/resources/jre-mac/man/man1/._jhsdb.1 +open-fin-al/resources/jre-mac/man/man1/._jinfo.1 +open-fin-al/resources/jre-mac/man/man1/._jlink.1 +open-fin-al/resources/jre-mac/man/man1/._jmap.1 +open-fin-al/resources/jre-mac/man/man1/._jmod.1 +open-fin-al/resources/jre-mac/man/man1/._jnativescan.1 +open-fin-al/resources/jre-mac/man/man1/._jpackage.1 +open-fin-al/resources/jre-mac/man/man1/._jps.1 +open-fin-al/resources/jre-mac/man/man1/._jshell.1 +open-fin-al/resources/jre-mac/man/man1/._jstack.1 +open-fin-al/resources/jre-mac/man/man1/._jstat.1 +open-fin-al/resources/jre-mac/man/man1/._jstatd.1 +open-fin-al/resources/jre-mac/man/man1/._jwebserver.1 +open-fin-al/resources/jre-mac/man/man1/._keytool.1 +open-fin-al/resources/jre-mac/man/man1/._rmiregistry.1 +open-fin-al/resources/jre-mac/man/man1/._serialver.1 +open-fin-al/resources/neo4j-mac/._bin +open-fin-al/resources/neo4j-mac/._certificates +open-fin-al/resources/neo4j-mac/._conf +open-fin-al/resources/neo4j-mac/._data +open-fin-al/resources/neo4j-mac/._import +open-fin-al/resources/neo4j-mac/._labs +open-fin-al/resources/neo4j-mac/._lib +open-fin-al/resources/neo4j-mac/._LICENSE.txt +open-fin-al/resources/neo4j-mac/._licenses +open-fin-al/resources/neo4j-mac/._logs +open-fin-al/resources/neo4j-mac/._packaging_info +open-fin-al/resources/neo4j-mac/._plugins +open-fin-al/resources/neo4j-mac/._products +open-fin-al/resources/neo4j-mac/._README.txt +open-fin-al/resources/neo4j-mac/._run +open-fin-al/resources/neo4j-mac/._ThirdPartyLicenses.txt +open-fin-al/resources/neo4j-mac/._UPGRADE.txt +open-fin-al/resources/neo4j-mac/._web +open-fin-al/resources/neo4j-mac/ThirdPartyLicenses.txt +open-fin-al/resources/neo4j-mac/bin/._completion +open-fin-al/resources/neo4j-mac/bin/._cypher-shell +open-fin-al/resources/neo4j-mac/bin/._neo4j +open-fin-al/resources/neo4j-mac/bin/._neo4j-admin +open-fin-al/resources/neo4j-mac/bin/completion/._neo4j_completion +open-fin-al/resources/neo4j-mac/bin/completion/._neo4j-admin_completion +open-fin-al/resources/neo4j-mac/conf/._neo4j-admin.conf +open-fin-al/resources/neo4j-mac/conf/._neo4j.conf +open-fin-al/resources/neo4j-mac/conf/._server-logs.xml +open-fin-al/resources/neo4j-mac/conf/._user-logs.xml +open-fin-al/resources/neo4j-mac/data/._.DS_Store +open-fin-al/resources/neo4j-mac/data/._databases +open-fin-al/resources/neo4j-mac/data/._transactions +open-fin-al/resources/neo4j-mac/labs/._apoc-2026.03.1-core.jar +open-fin-al/resources/neo4j-mac/labs/._LICENSE +open-fin-al/resources/neo4j-mac/labs/._README.txt +open-fin-al/resources/neo4j-mac/labs/apoc-2026.03.1-core.jar +open-fin-al/resources/neo4j-mac/lib/._annotations-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._antlr4-runtime-4.13.2.jar +open-fin-al/resources/neo4j-mac/lib/._argparse4j-0.9.0.jar +open-fin-al/resources/neo4j-mac/lib/._asm-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/._asm-analysis-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/._asm-tree-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/._asm-util-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/._caffeine-3.2.3.jar +open-fin-al/resources/neo4j-mac/lib/._commons-codec-1.21.0.jar +open-fin-al/resources/neo4j-mac/lib/._commons-compress-1.28.0.jar +open-fin-al/resources/neo4j-mac/lib/._commons-configuration2-2.13.0.jar +open-fin-al/resources/neo4j-mac/lib/._commons-io-2.21.0.jar +open-fin-al/resources/neo4j-mac/lib/._commons-lang3-3.20.0.jar +open-fin-al/resources/neo4j-mac/lib/._commons-logging-1.3.5.jar +open-fin-al/resources/neo4j-mac/lib/._commons-pool-1.6.jar +open-fin-al/resources/neo4j-mac/lib/._commons-text-1.15.0.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-antlr-ast-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-antlr-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-parser-ast-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-parser-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-parser-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-preparser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-shell-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v5-antlr-parser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v5-ast-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v5-literal-interpreter-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v5-parser-listener-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v25-antlr-parser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v25-ast-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._cypher-v25-parser-listener-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._eclipse-collections-11.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._eclipse-collections-api-11.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._FastInfoset-1.2.16.jar +open-fin-al/resources/neo4j-mac/lib/._hk2-api-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/._hk2-locator-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/._hk2-utils-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/._ipaddress-5.6.1.jar +open-fin-al/resources/neo4j-mac/lib/._istack-commons-runtime-3.0.8.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-annotations-2.21.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-core-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-databind-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-jaxrs-base-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-jaxrs-json-provider-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/._jackson-module-jaxb-annotations-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.activation-api-1.2.2.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.annotation-api-1.3.5.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.inject-2.6.1.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.validation-api-2.0.2.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.ws.rs-api-2.1.6.jar +open-fin-al/resources/neo4j-mac/lib/._jakarta.xml.bind-api-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._jansi-2.4.0.jar +open-fin-al/resources/neo4j-mac/lib/._java-jwt-4.5.0.jar +open-fin-al/resources/neo4j-mac/lib/._javassist-3.30.2-GA.jar +open-fin-al/resources/neo4j-mac/lib/._javax.annotation-api-1.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._jaxb-api-2.2.12.jar +open-fin-al/resources/neo4j-mac/lib/._jaxb-runtime-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._jctools-core-4.0.5.jar +open-fin-al/resources/neo4j-mac/lib/._jersey-client-2.46.jar +open-fin-al/resources/neo4j-mac/lib/._jersey-container-servlet-2.46.jar +open-fin-al/resources/neo4j-mac/lib/._jersey-container-servlet-core-2.46.jar +open-fin-al/resources/neo4j-mac/lib/._jersey-hk2-2.46.jar +open-fin-al/resources/neo4j-mac/lib/._jersey-server-2.46.jar +open-fin-al/resources/neo4j-mac/lib/._jettison-1.5.4.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-alpn-java-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-alpn-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-ee-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-ee8-nested-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-ee8-security-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-ee8-servlet-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-ee8-webapp-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-http-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-http2-common-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-http2-hpack-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-http2-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-io-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-security-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-servlet-api-4.0.9.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-session-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-util-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jetty-xml-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/._jline-reader-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/._jline-terminal-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/._jline-terminal-jansi-3.21.0.jar +open-fin-al/resources/neo4j-mac/lib/._jna-5.18.1.jar +open-fin-al/resources/neo4j-mac/lib/._jPowerShell-3.0.jar +open-fin-al/resources/neo4j-mac/lib/._jProcesses-1.6.5.jar +open-fin-al/resources/neo4j-mac/lib/._jspecify-1.0.0.jar +open-fin-al/resources/neo4j-mac/lib/._jts-core-1.20.0.jar +open-fin-al/resources/neo4j-mac/lib/._kiama_2.13-2.5.1.jar +open-fin-al/resources/neo4j-mac/lib/._log4j-api-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/._log4j-core-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/._log4j-layout-template-json-2.25.3.jar +open-fin-al/resources/neo4j-mac/lib/._lucene-analysis-common-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._lucene-backward-codecs-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._lucene-core-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._lucene-queryparser-10.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._lucene9-shaded-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._magnolia_2.13-1.1.8.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-ast-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-connection-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-connection-netty-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-connection-pooled-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-connection-routed-10.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bolt-messages-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-bootcheck-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-capabilities-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cloud-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-codegen-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-collections-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-command-line-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-concurrent-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-configuration-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-consistency-check-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-csv-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-admin-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-cache-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-config-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-dsl-2025.2.3.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-expression-evaluator-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-interpreted-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-ir-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-logical-plans-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-macros-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-physical-planning-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-planner-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-planner-spi-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-rendering-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-runtime-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-cypher-slotted-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-data-collector-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-dbms-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-diagnostics-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-exceptions-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-expressions-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-fabric-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-fleet-management-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-front-end-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-gql-status-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-graph-algo-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-graphdb-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-id-generator-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-import-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-import-tool-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-import-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-internal-notifications-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-io-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-java-driver-6.0.2.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-kernel-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-kernel-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-layout-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-lock-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-logging-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-lucene-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-monitoring-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-native-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-notifications-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-procedure-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-procedure-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-push-to-cloud-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-query-router-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-record-storage-engine-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-resource-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-rewriting-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-schema-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-security-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-server-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-slf4j-provider-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-spatial-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-ssl-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-storage-engine-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-token-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-udc-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-unsafe-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-values-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._neo4j-wal-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._netty-buffer-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-codec-base-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-codec-compression-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-codec-http-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-common-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-handler-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-resolver-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-tcnative +open-fin-al/resources/neo4j-mac/lib/._netty-tcnative-classes-2.0.75.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-classes-epoll-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-classes-kqueue-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-native-epoll-4.2.10.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-native-epoll-4.2.10.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-native-kqueue-4.2.10.Final-osx-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-native-kqueue-4.2.10.Final-osx-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/._netty-transport-native-unix-common-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-column-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-common-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-encoding-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-floor-1.60.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-format-structures-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-hadoop-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._parquet-jackson-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/._picocli-4.7.7.jar +open-fin-al/resources/neo4j-mac/lib/._reactive-streams-1.0.4.jar +open-fin-al/resources/neo4j-mac/lib/._reactor-core-3.8.3.jar +open-fin-al/resources/neo4j-mac/lib/._scala-collection-contrib_2.13-0.3.0.jar +open-fin-al/resources/neo4j-mac/lib/._scala-library-2.13.17.jar +open-fin-al/resources/neo4j-mac/lib/._scala-reflect-2.13.17.jar +open-fin-al/resources/neo4j-mac/lib/._server-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-cache-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-config-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-crypto-cipher-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-crypto-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-crypto-hash-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-event-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-hashes-argon2-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-hashes-bcrypt-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._shiro-lang-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/._slf4j-api-2.0.17.jar +open-fin-al/resources/neo4j-mac/lib/._snappy-java-1.1.10.7.jar +open-fin-al/resources/neo4j-mac/lib/._sourcecode_2.13-0.4.2.jar +open-fin-al/resources/neo4j-mac/lib/._stax-ex-1.8.1.jar +open-fin-al/resources/neo4j-mac/lib/._txw2-2.3.2.jar +open-fin-al/resources/neo4j-mac/lib/._WMI4Java-1.6.3.jar +open-fin-al/resources/neo4j-mac/lib/._zstd-jni-1.5.7-7.jar +open-fin-al/resources/neo4j-mac/lib/._zstd-proxy-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/annotations-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/asm-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/asm-analysis-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/asm-tree-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/asm-util-9.9.1.jar +open-fin-al/resources/neo4j-mac/lib/commons-codec-1.21.0.jar +open-fin-al/resources/neo4j-mac/lib/cypher-antlr-ast-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-antlr-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-ast-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-parser-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-preparser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-shell-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-antlr-parser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-ast-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-literal-interpreter-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v5-parser-listener-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-antlr-parser-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-ast-factory-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/cypher-v25-parser-listener-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/ipaddress-5.6.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-annotations-2.21.jar +open-fin-al/resources/neo4j-mac/lib/jackson-core-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-databind-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-jaxrs-base-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-jaxrs-json-provider-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/jackson-module-jaxb-annotations-2.21.1.jar +open-fin-al/resources/neo4j-mac/lib/jetty-alpn-java-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-alpn-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-nested-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-security-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-servlet-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-ee8-webapp-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-common-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-hpack-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-http2-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-io-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-security-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-server-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-servlet-api-4.0.9.jar +open-fin-al/resources/neo4j-mac/lib/jetty-session-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-util-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jetty-xml-12.0.33.jar +open-fin-al/resources/neo4j-mac/lib/jspecify-1.0.0.jar +open-fin-al/resources/neo4j-mac/lib/lucene9-shaded-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-ast-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bolt-messages-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-bootcheck-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-capabilities-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cloud-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-codegen-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-collections-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-command-line-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-common-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-concurrent-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-configuration-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-consistency-check-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-csv-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-admin-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-cache-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-config-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-dsl-2025.2.3.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-expression-evaluator-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-interpreted-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-ir-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-logical-plans-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-macros-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-physical-planning-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-planner-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-planner-spi-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-rendering-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-runtime-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-cypher-slotted-runtime-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-data-collector-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-dbms-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-diagnostics-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-exceptions-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-expressions-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-fabric-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-fleet-management-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-front-end-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-gql-status-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-graph-algo-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-graphdb-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-id-generator-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-tool-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-import-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-internal-notifications-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-io-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-kernel-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-kernel-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-layout-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-lock-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-logging-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-lucene-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-monitoring-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-native-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-notifications-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-procedure-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-procedure-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-push-to-cloud-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-query-router-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-record-storage-engine-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-resource-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-rewriting-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-schema-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-security-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-server-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-slf4j-provider-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-spatial-index-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-ssl-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-storage-engine-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-token-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-udc-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-unsafe-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-util-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-values-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/neo4j-wal-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/netty-buffer-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-base-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-compression-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-codec-http-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-common-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-handler-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-resolver-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative-classes-2.0.75.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-classes-epoll-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-classes-kqueue-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-epoll-4.2.10.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-epoll-4.2.10.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-kqueue-4.2.10.Final-osx-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-kqueue-4.2.10.Final-osx-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-transport-native-unix-common-4.2.10.Final.jar +open-fin-al/resources/neo4j-mac/lib/parquet-column-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-common-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-encoding-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-floor-1.60.jar +open-fin-al/resources/neo4j-mac/lib/parquet-format-structures-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-hadoop-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/parquet-jackson-1.17.0.jar +open-fin-al/resources/neo4j-mac/lib/reactor-core-3.8.3.jar +open-fin-al/resources/neo4j-mac/lib/server-api-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/shiro-cache-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-config-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-cipher-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-core-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-crypto-hash-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-event-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-hashes-argon2-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-hashes-bcrypt-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/shiro-lang-2.1.0.jar +open-fin-al/resources/neo4j-mac/lib/sourcecode_2.13-0.4.2.jar +open-fin-al/resources/neo4j-mac/lib/zstd-jni-1.5.7-7.jar +open-fin-al/resources/neo4j-mac/lib/zstd-proxy-2026.03.1.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/._netty-tcnative-2.0.75.Final-linux-aarch_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/._netty-tcnative-2.0.75.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/._netty-tcnative-2.0.75.Final-linux-x86_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/._netty-tcnative-2.0.75.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/._netty-tcnative-2.0.75.Final.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.75.Final-linux-aarch_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.75.Final-linux-aarch_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.75.Final-linux-x86_64-fedora.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.75.Final-linux-x86_64.jar +open-fin-al/resources/neo4j-mac/lib/netty-tcnative/netty-tcnative-2.0.75.Final.jar +open-fin-al/resources/neo4j-mac/plugins/._README.txt +open-fin-al/resources/neo4j-mac/products/._neo4j-genai-plugin-2026.03.1.jar +open-fin-al/resources/neo4j-mac/products/._neo4j-graph-data-science-2026.03.0.jar +open-fin-al/resources/neo4j-mac/products/neo4j-genai-plugin-2026.03.1.jar +open-fin-al/resources/neo4j-mac/products/neo4j-graph-data-science-2026.03.0.jar +open-fin-al/resources/neo4j-mac/web/._neo4j-browser-2026.03.23+0.zip +open-fin-al/resources/neo4j-mac/web/neo4j-browser-2026.03.23+0.zip +open-fin-al/src/tests/ChatbotCommandHandler.test.ts +open-fin-al/resources/neo4j-mac/lib/._jersey-common-2.46.jar diff --git a/documentation/code_related/guides/creating-a-new-component.md b/documentation/code_related/guides/creating-a-new-component.md new file mode 100644 index 00000000..7549a8df --- /dev/null +++ b/documentation/code_related/guides/creating-a-new-component.md @@ -0,0 +1,286 @@ +# Creating a New Component in OpenFinAL + +All UI components in OpenFinAL are wrapped with the `withViewComponent` HOC. This gives every component: + +- Visibility control (`visible: false` hides it without removing it from the tree) +- Enabled/disabled state (grays out and blocks interaction) +- Automatic fixed dimensions for aspect-ratio-sensitive components (charts, slideshows) +- Auto-sizing (`height: auto`, `width: 100%`) for content-flow components (lists, forms, rows) +- Registration in the `ComponentRegistry` so the AI chatbot can find and mutate it by natural language + +There are two component types: + +| Type | File extension | When to use | +|---|---|---| +| JSX component | `.jsx` | Standard React component, no TypeScript prop enforcement | +| TSX component | `.tsx` | When you need TypeScript interface checking on props | + +--- + +## Part 1: Creating a JSX Component + +### Step 1 — Create the component file + +Place the file in the appropriate subdirectory under `open-fin-al/src/View/`. + +**Example:** `open-fin-al/src/View/Dashboard/MyWidget.jsx` + +```jsx +import React from "react"; + +// The component receives viewConfig automatically from the HOC wrapper. +// You do not need to use viewConfig inside the component unless you need +// to read dimension or ratio values (e.g. for canvas sizing). +export function MyWidget({ viewConfig, someOtherProp }) { + return ( +
+

{someOtherProp}

+
+ ); +} +``` + +> **Note:** Do not call `withViewComponent` inside this file if this component will be exported from `WrappedComponents.ts`. Doing so creates a circular dependency. See the circular dependency warning below. + +--- + +### Step 2 — Add to `WrappedComponents.ts` + +Open `open-fin-al/src/hoc/WrappedComponents.ts` and add an import and a wrapped export under the appropriate section comment. + +```ts +// Dashboard +import { MyWidget } from "../View/Dashboard/MyWidget"; + +export const WrappedMyWidget = withViewComponent(MyWidget); +``` + +--- + +### Step 3 — Register in `registerComponents.ts` + +Open `open-fin-al/src/hoc/registerComponents.ts` and add an entry to the `componentConfigs` array. This registers the component in the `ComponentRegistry` so the AI chatbot can find it. + +```ts +{ + id: "my-widget", + config: { + label: "My Widget", + description: "Short description of what the widget does — used by AI search", + tags: ["widget", "dashboard", "relevant-keyword"], + height: 200, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, // true = fixed pixel dims; false = auto/100% + widthRatio: 2, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, +}, +``` + +**`maintainAspectRatio` guide:** +- `true` — the HOC sets explicit `height` and `width` in pixels. Use this for charts, slideshows, and any component where pixel dimensions matter. +- `false` — the HOC sets `height: "auto"` and `width: "100%"`. Use this for lists, rows, forms, and anything that should flow with its content. + +--- + +### Step 4 — Use the wrapped component + +Import the wrapped version from `WrappedComponents.ts` in any page file that is **not itself exported from `WrappedComponents.ts`**. + +```jsx +import { WrappedMyWidget } from "../hoc/WrappedComponents"; +import { useMemo } from "react"; +import { ViewComponent } from "../types/ViewComponent"; + +function SomePage() { + const myWidgetConfig = useMemo(() => new ViewComponent({ + height: 200, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 2, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "My Widget", description: "...", + tags: ["widget"], minimumProficiencyRequirements: {}, requiresInternet: false, + }), []); + + return ; +} +``` + +> Use `useMemo` for the config in functional components so a new `ViewComponent` instance is not created on every render. For class components, define the config as a class property instead (see the circular dependency section below). + +--- + +## Part 2: Creating a TSX Component + +TSX components work exactly the same way as JSX, but you define a TypeScript interface for the props. This ensures callers pass the correct props at compile time. + +### Step 1 — Create the component file + +Place it under `open-fin-al/src/View/Component/
/` for sub-components, or directly in `open-fin-al/src/View/
/` for page-level components. + +**Example:** `open-fin-al/src/View/Component/Dashboard/MyChart.tsx` + +```tsx +import React from "react"; +import { withViewComponent, WithViewComponentProps } from "../../../hoc/withViewComponent"; + +// 1. Declare your own props and extend WithViewComponentProps. +// WithViewComponentProps contributes: viewConfig: ViewComponent +interface MyChartProps extends WithViewComponentProps { + data: number[]; + label: string; +} + +// 2. Write the inner component (not exported directly). +function MyChartInner({ data, label, viewConfig }: MyChartProps) { + return ( +
+

{label}

+ {/* use data to render chart */} +
+ ); +} + +// 3. Export the wrapped version. +export const MyChart = withViewComponent(MyChartInner); +``` + +> The inner function is **not** exported. Only the wrapped export is public. This prevents accidental use of the unwrapped version. + +--- + +### Step 2 — Add to `WrappedComponents.ts` + +```ts +// Dashboard +import { MyChart } from "../View/Component/Dashboard/MyChart"; + +export const WrappedMyChart = withViewComponent(MyChart); +``` + +Wait — `MyChart` is already wrapped inside its `.tsx` file. **Do not double-wrap it.** Instead, just re-export it with the `Wrapped` naming convention for consistency: + +```ts +// Dashboard +export { MyChart as WrappedMyChart } from "../View/Component/Dashboard/MyChart"; +``` + +Or skip `WrappedComponents.ts` entirely for TSX components and import directly from the source file: + +```tsx +import { MyChart } from "../View/Component/Dashboard/MyChart"; +``` + +--- + +### Step 3 — Register in `registerComponents.ts` + +Same as JSX — add an entry to `componentConfigs` in `open-fin-al/src/hoc/registerComponents.ts`. + +```ts +{ + id: "my-chart", + config: { + label: "My Chart", + description: "Displays data as a chart", + tags: ["chart", "dashboard", "data"], + height: 300, + width: 700, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, +}, +``` + +--- + +### Step 4 — Use the component + +```tsx +import { MyChart } from "../View/Component/Dashboard/MyChart"; +import { useMemo } from "react"; +import { ViewComponent } from "../types/ViewComponent"; + +function SomePage() { + const chartConfig = useMemo(() => new ViewComponent({ + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "My Chart", description: "...", + tags: ["chart"], minimumProficiencyRequirements: {}, requiresInternet: false, + }), []); + + return ; +} +``` + +TypeScript will error at compile time if you forget `data`, `label`, or `viewConfig`, or if you pass the wrong type. + +--- + +## Circular Dependency Warning + +**Rule:** Any file that is exported from `WrappedComponents.ts` must NOT import from `WrappedComponents.ts`. + +If a page-level component (e.g. `Home.jsx`, `Settings.jsx`) is listed in `WrappedComponents.ts` AND also needs to render a wrapped sub-component, it cannot use `WrappedComponents.ts` as the import source. Instead, wrap locally inside that file: + +```jsx +// At the top of Home.jsx — wrap locally instead of importing from WrappedComponents +import { withViewComponent } from "../hoc/withViewComponent"; +import { NewsBrowser } from "./News/Browser"; + +const WrappedNewsBrowser = withViewComponent(NewsBrowser); +``` + +For class components that cannot use `useMemo`, define the config as a class property: + +```jsx +class Home extends Component { + newsBrowserConfig = new ViewComponent({ + height: 300, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "News Browser", description: "...", + tags: ["news"], minimumProficiencyRequirements: {}, requiresInternet: true, + }); + + render() { + return ; + } +} +``` + +--- + +## Summary Checklist + +### JSX component +- [ ] Create `open-fin-al/src/View/
/MyComponent.jsx` and export a named function +- [ ] Add import + `withViewComponent` export to `open-fin-al/src/hoc/WrappedComponents.ts` +- [ ] Add a config entry to `open-fin-al/src/hoc/registerComponents.ts` +- [ ] Use `WrappedMyComponent` with a `viewConfig` prop at the call site + +### TSX component +- [ ] Create `open-fin-al/src/View/Component/
/MyComponent.tsx` +- [ ] Define `interface MyComponentProps extends WithViewComponentProps { ... }` +- [ ] Write the inner function (unexported), call `withViewComponent(Inner)` and export the result +- [ ] Add a config entry to `open-fin-al/src/hoc/registerComponents.ts` +- [ ] Use the exported component directly with a `viewConfig` prop at the call site + +### Both +- [ ] Set `maintainAspectRatio: true` only for components that need fixed pixel dimensions (charts, slideshows) +- [ ] Never import from `WrappedComponents.ts` inside a file that is itself exported from `WrappedComponents.ts` diff --git a/open-fin-al/package.json b/open-fin-al/package.json index ae362802..6bbd4062 100644 --- a/open-fin-al/package.json +++ b/open-fin-al/package.json @@ -45,6 +45,7 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/jest": "^30.0.0", + "@types/react": "^19.2.7", "@vercel/webpack-asset-relocator-loader": "^1.7.3", "babel-loader": "^10.0.0", "browserify-fs": "^1.0.0", @@ -72,6 +73,7 @@ "cors": "^2.8.5", "crypto": "^1.0.1", "crypto-browserify": "^3.12.1", + "danfojs": "^1.2.0", "electron-squirrel-startup": "^1.0.1", "events": "^3.3.0", "express": "^5.1.0", @@ -80,6 +82,7 @@ "http": "^0.0.1-security", "https": "^1.0.0", "keytar": "^7.9.0", + "neo4j-driver": "^6.0.1", "node-html-parser": "^7.0.1", "os-browserify": "^0.3.0", "pptx-preview": "^1.0.7", diff --git a/open-fin-al/resources/README.md b/open-fin-al/resources/README.md new file mode 100644 index 00000000..9ae32618 --- /dev/null +++ b/open-fin-al/resources/README.md @@ -0,0 +1,3 @@ +## Purpose of this Folder +The resources folder should contain the following folders: +neo4j-win - this folder should include binaries for neo4j community for Windows \ No newline at end of file diff --git a/open-fin-al/resources/slideshows/IntroductionToInvesting.pptx b/open-fin-al/resources/slideshows/IntroductionToInvesting.pptx new file mode 100644 index 00000000..9ab38894 Binary files /dev/null and b/open-fin-al/resources/slideshows/IntroductionToInvesting.pptx differ diff --git a/open-fin-al/src/Asset/Image/ai_header.png b/open-fin-al/src/Asset/Image/ai_header.png new file mode 100644 index 00000000..063e217b Binary files /dev/null and b/open-fin-al/src/Asset/Image/ai_header.png differ diff --git a/open-fin-al/src/Asset/Image/binary_header.png b/open-fin-al/src/Asset/Image/binary_header.png new file mode 100644 index 00000000..6f880048 Binary files /dev/null and b/open-fin-al/src/Asset/Image/binary_header.png differ diff --git a/open-fin-al/src/Asset/Image/thumbnail_unavailable.png b/open-fin-al/src/Asset/Image/thumbnail_unavailable.png new file mode 100644 index 00000000..09da10bb Binary files /dev/null and b/open-fin-al/src/Asset/Image/thumbnail_unavailable.png differ diff --git a/open-fin-al/src/Gateway/Data/EconomicGateway/AlphaVantageEconomicGateway.ts b/open-fin-al/src/Gateway/Data/EconomicGateway/AlphaVantageEconomicGateway.ts index a951711a..c060c05d 100644 --- a/open-fin-al/src/Gateway/Data/EconomicGateway/AlphaVantageEconomicGateway.ts +++ b/open-fin-al/src/Gateway/Data/EconomicGateway/AlphaVantageEconomicGateway.ts @@ -27,7 +27,10 @@ export class AlphaVantageEconomicGateway implements IKeyedDataGateway { throw new Error("This gateway does not have the ability to post content"); } - async read(entity: IEntity, action: string): Promise> { + async read(entity: IEntity, action: string): Promise> { + const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms)); + await sleep(1001); + var url = `${this.baseURL}?`; if(action==="getGDP") { diff --git a/open-fin-al/src/Gateway/Data/ICredentialedDataGateway.ts b/open-fin-al/src/Gateway/Data/ICredentialedDataGateway.ts new file mode 100644 index 00000000..be5bbe73 --- /dev/null +++ b/open-fin-al/src/Gateway/Data/ICredentialedDataGateway.ts @@ -0,0 +1,14 @@ +import {IEntity} from "../../Entity/IEntity"; +import { IDataGateway } from "./IDataGateway"; + +export interface ICredentialedDataGateway extends IDataGateway { + user: string; + key: string; + sourceName: string; + connect(): void; + disconnect(): void; + create(entity: IEntity, action?: string): Promise; + read(entity: IEntity, action?: string): Promise>; + update(entity: IEntity, action?: string): Promise; + delete(entity: IEntity, action?: string): Promise; +} \ No newline at end of file diff --git a/open-fin-al/src/Gateway/Data/IDataGateway.ts b/open-fin-al/src/Gateway/Data/IDataGateway.ts index 8617fdd5..a74f2b89 100644 --- a/open-fin-al/src/Gateway/Data/IDataGateway.ts +++ b/open-fin-al/src/Gateway/Data/IDataGateway.ts @@ -1,6 +1,7 @@ import {IEntity} from "../../Entity/IEntity"; export interface IDataGateway { + user?: string; key?: string; sourceName: string; connect(): void; diff --git a/open-fin-al/src/Gateway/Data/IKeylessDataGateway.ts b/open-fin-al/src/Gateway/Data/IKeylessDataGateway.ts index eb82485c..9705bbb3 100644 --- a/open-fin-al/src/Gateway/Data/IKeylessDataGateway.ts +++ b/open-fin-al/src/Gateway/Data/IKeylessDataGateway.ts @@ -3,8 +3,8 @@ import { IDataGateway } from "./IDataGateway"; export interface IKeylessDataGateway extends IDataGateway { sourceName: string; - connect(): void; - disconnect(): void; + connect(): void | Promise | Promise; + disconnect(): void | Promise | Promise; create(entity: IEntity, action?: string): Promise; read(entity: IEntity, action?: string): Promise>; update(entity: IEntity, action?: string): Promise; diff --git a/open-fin-al/src/Gateway/Data/INeo4JGraphGateway.ts b/open-fin-al/src/Gateway/Data/INeo4JGraphGateway.ts new file mode 100644 index 00000000..6685bf75 --- /dev/null +++ b/open-fin-al/src/Gateway/Data/INeo4JGraphGateway.ts @@ -0,0 +1,17 @@ +import {IEntity} from "../../Entity/IEntity"; +import { IDataGateway } from "./IDataGateway"; + +export interface INeo4JGraphGateway extends IDataGateway { + user: string; + key: string; + sourceName: string; + connect(): Promise; + disconnect(): Promise; + create(entity: IEntity, action?: string): Promise; + read(entity: IEntity, action?: string): Promise>; + update(entity: IEntity, action?: string): Promise; + delete(entity: IEntity, action?: string): Promise; + checkGraphConnected(): Promise; + checkGraphExists(): Promise; + checkLastGraphUpdate() : Promise; +} \ No newline at end of file diff --git a/open-fin-al/src/Gateway/Data/MarketGateway/AlphaVantagMarketGateway.ts b/open-fin-al/src/Gateway/Data/MarketGateway/AlphaVantagMarketGateway.ts index 27f683cd..1986424b 100644 --- a/open-fin-al/src/Gateway/Data/MarketGateway/AlphaVantagMarketGateway.ts +++ b/open-fin-al/src/Gateway/Data/MarketGateway/AlphaVantagMarketGateway.ts @@ -29,6 +29,9 @@ export class AlphaVantageMarketGateway implements IKeyedDataGateway { } async read(entity: IEntity, action: string): Promise> { + const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms)); + await sleep(1001); + var url = `${this.baseURL}?function=MARKET_STATUS&apikey=${entity.getFieldValue("key")}`; const urlObject = new URL(url); diff --git a/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphCreationGateway.ts b/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphCreationGateway.ts new file mode 100644 index 00000000..f838d6e4 --- /dev/null +++ b/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphCreationGateway.ts @@ -0,0 +1,211 @@ +import neo4j, {Record, Node} from "neo4j-driver"; +import { INeo4JGraphGateway } from "../INeo4JGraphGateway"; +import { IEntity } from "@Entity/IEntity"; + +declare global { + interface Window { + neo4j: any + } +} + +export class Neo4JGraphCreationGateway implements INeo4JGraphGateway { + user: string = ""; + key: string = ""; + connection: any = null; + sourceName: string = "Neo4j Local Database"; + + async connect(): Promise { + try { + return await window.neo4j.start(); + } catch (error) { + console.error("Error connecting to Neo4j server:", error); + return false; + } + } + + async disconnect(): Promise { + try { + return await window.neo4j.stop(); + } catch (error) { + console.error("Error disconnecting from Neo4j server:", error); + return false; + } + } + + // used to create and periodically refresh the cache + async create(): Promise { + const schema: string[] = [ + `CREATE CONSTRAINT user_userId_unique IF NOT EXISTS + FOR (u:User) + REQUIRE u.userId IS UNIQUE`, + + `CREATE CONSTRAINT module_moduleId_unique IF NOT EXISTS + FOR (m:Module) + REQUIRE m.moduleId IS UNIQUE`, + + `CREATE CONSTRAINT concept_conceptId_unique IF NOT EXISTS + FOR (c:Concept) + REQUIRE c.conceptId IS UNIQUE`, + + `CREATE INDEX module_minLevel IF NOT EXISTS + FOR (m:Module) ON (m.minLevel)`, + + `CREATE INDEX module_riskTag IF NOT EXISTS + FOR (m:Module) ON (m.riskTag)`, + ]; + + const merges: string[] = [ + `MERGE (u1:User { userId: "u_alice" }) + SET u1.overallLevel = 2, + u1.riskScore = 2`, + + `MERGE (u2:User { userId: "u_bob" }) + SET u2.overallLevel = 1, + u2.riskScore = 1`, + + `MERGE (c_etf:Concept { conceptId: "c_etf", name: "ETFs" })`, + `MERGE (c_div:Concept { conceptId: "c_div", name: "Dividends" })`, + `MERGE (c_opt:Concept { conceptId: "c_opt", name: "Options" })`, + `MERGE (c_cc:Concept { conceptId: "c_cc", name: "Covered Calls" })`, + `MERGE (c_risk:Concept{ conceptId: "c_risk",name: "Risk Management" })`, + + `MERGE (m1:Module { moduleId: "m_etf_basics" }) + SET m1.title = "ETF Basics", + m1.description = "Introduction to exchange-traded funds", + m1.timeEstimate = 45, + m1.minLevel = 1, + m1.riskTag = 1`, + + `MERGE (m2:Module { moduleId: "m_div_income" }) + SET m2.title = "Dividend Investing", + m2.description = "Building income with dividends", + m2.timeEstimate = 60, + m2.minLevel = 2, + m2.riskTag = 1`, + + `MERGE (m3:Module { moduleId: "m_options_101" }) + SET m3.title = "Options 101", + m3.description = "Foundations of options trading", + m3.timeEstimate = 90, + m3.minLevel = 3, + m3.riskTag = 3`, + + `MERGE (m4:Module { moduleId: "m_covered_calls" }) + SET m4.title = "Covered Call Strategies", + m4.description = "Generating income with covered calls", + m4.timeEstimate = 75, + m4.minLevel = 3, + m4.riskTag = 2`, + + `MATCH (m1:Module {moduleId:"m_etf_basics"}), + (c_etf:Concept {conceptId:"c_etf"}) + MERGE (m1)-[:TEACHES {weight: 1.0}]->(c_etf)`, + + `MATCH (m2:Module {moduleId:"m_div_income"}), + (c_div:Concept {conceptId:"c_div"}), + (c_etf:Concept {conceptId:"c_etf"}) + MERGE (m2)-[:TEACHES {weight: 0.7}]->(c_div) + MERGE (m2)-[:TEACHES {weight: 0.3}]->(c_etf)`, + + `MATCH (m3:Module {moduleId:"m_options_101"}), + (c_opt:Concept {conceptId:"c_opt"}), + (c_risk:Concept {conceptId:"c_risk"}) + MERGE (m3)-[:TEACHES {weight: 0.7}]->(c_opt) + MERGE (m3)-[:TEACHES {weight: 0.3}]->(c_risk)`, + + `MATCH (m4:Module {moduleId:"m_covered_calls"}), + (c_cc:Concept {conceptId:"c_cc"}), + (c_opt:Concept {conceptId:"c_opt"}) + MERGE (m4)-[:TEACHES {weight: 0.6}]->(c_cc) + MERGE (m4)-[:TEACHES {weight: 0.4}]->(c_opt)`, + + `MATCH (m2:Module {moduleId:"m_div_income"}), + (m1:Module {moduleId:"m_etf_basics"}) + MERGE (m2)-[:REQUIRES {strict:true}]->(m1)`, + + `MATCH (m3:Module {moduleId:"m_options_101"}), + (m1:Module {moduleId:"m_etf_basics"}) + MERGE (m3)-[:REQUIRES {strict:true}]->(m1)`, + + `MATCH (m4:Module {moduleId:"m_covered_calls"}), + (m3:Module {moduleId:"m_options_101"}) + MERGE (m4)-[:REQUIRES {strict:true}]->(m3)`, + + `MATCH (u:User {userId:"u_alice"}), + (c_etf:Concept {conceptId:"c_etf"}), + (c_div:Concept {conceptId:"c_div"}) + MERGE (u)-[:KNOWS {level:2, confidence:0.8, updatedAt:datetime()}]->(c_etf) + MERGE (u)-[:KNOWS {level:1, confidence:0.6, updatedAt:datetime()}]->(c_div)`, + + `MATCH (u:User {userId:"u_bob"}), + (c_etf:Concept {conceptId:"c_etf"}) + MERGE (u)-[:KNOWS {level:1, confidence:0.5, updatedAt:datetime()}]->(c_etf)`, + + `MATCH (u:User {userId:"u_alice"}), + (m1:Module {moduleId:"m_etf_basics"}) + MERGE (u)-[:COMPLETED {at:datetime()}]->(m1)`, + + `MATCH (u:User {userId:"u_bob"}), + (m1:Module {moduleId:"m_etf_basics"}) + MERGE (u)-[:COMPLETED {at:datetime()}]->(m1)`, + ]; + + try { + await window.neo4j.executeQuery("write", schema); + await window.neo4j.executeQuery("write", merges); + return true; + } catch(error) { + window.console.error("Error creating graph schema/data in Neo4j server:", error); + return false; + } + } + + async read(): Promise { + throw new Error("This gatweay does not allow for reading. This gateway is designed for posting only."); + } + + update(entity: IEntity, action: string): Promise { + throw new Error("This gateway does not have the ability to update content. Updates are handled by periodically deleting and re-entering data"); + } + + async delete(entity: IEntity, action: string): Promise { + throw new Error("This gatweay does not allow deleting data. This gateway is designed for posting only."); + } + + //check to see if the database exists + async checkGraphExists(): Promise { + try { + const query = + `MATCH (n) + RETURN count(n) AS count` + ; + + const result = await window.neo4j.executeQuery("read", query); + window.console.log(result); + const count = result.records[0].count; + window.console.log(count); + if(count > 0) { + return true; + } else { + return false; + } + } catch(error) { + window.console.log(error); + return false; + } + } + + async checkGraphConnected():Promise { + try { + const isConnected = await window.neo4j.isConnected(); + return isConnected; + } catch(error) { + return false; + } + } + + //for database tables that act as cache, check for the last time a table was updated + async checkLastGraphUpdate():Promise { + throw new Error("This gatweay does not allow for checking tables. This gateway is designed for posting only."); + } +} \ No newline at end of file diff --git a/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphGateway.ts b/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphGateway.ts new file mode 100644 index 00000000..597a45fe --- /dev/null +++ b/open-fin-al/src/Gateway/Data/Neo4J/Neo4JGraphGateway.ts @@ -0,0 +1,66 @@ +import neo4j, {Record, Node} from "neo4j-driver"; +import {IEntity} from "../../../Entity/IEntity"; +import {ICredentialedDataGateway} from "../ICredentialedDataGateway"; + +declare global { + interface Window { + neo4j: any + } +} + +export class Neo4JGraphGateway implements ICredentialedDataGateway { + user: string = ""; + key: string = ""; + sourceName: string = "Neo4j Local Database"; + + async connect(): Promise { + try { + return await window.neo4j.start(); + } catch (error) { + console.error("Error connecting to Neo4j server:", error); + return false; + } + } + + async disconnect(): Promise { + try { + return await window.neo4j.stop(); + } catch (error) { + console.error("Error disconnecting from Neo4j server:", error); + return false; + } + } + + create(entity: IEntity, action: string): Promise { + //at the moment, users will not be permitted to create new graphs + throw new Error("Method not implemented."); + } + + async read(entity: IEntity, action: string): Promise { + const id:any = null; + try { + const query = + ` + MATCH (u:User { id: $id }) + RETURN u + ` + ; + + const results = await window.neo4j.executeQuery(query, {id: id}); + return results; + } catch (error) { + window.console.error("Error reading from Neo4j server:", error); + return null; + } + } + + update(entity: IEntity, action: string): Promise { + //at the moment, users will not be permitted to update graphs; + throw new Error("Method not implemented."); + } + + delete(entity: IEntity, action: string): Promise { + //at the moment, users will not be permitted to delete graphs + throw new Error("Method not implemented."); + } +} \ No newline at end of file diff --git a/open-fin-al/src/Gateway/Data/NewsGateway/AlphaVantageNewsGateway.ts b/open-fin-al/src/Gateway/Data/NewsGateway/AlphaVantageNewsGateway.ts index 128bf8ad..bae85171 100644 --- a/open-fin-al/src/Gateway/Data/NewsGateway/AlphaVantageNewsGateway.ts +++ b/open-fin-al/src/Gateway/Data/NewsGateway/AlphaVantageNewsGateway.ts @@ -28,6 +28,9 @@ export class AlphaVantageNewsGateway implements IKeyedDataGateway { } async read(entity: IEntity, action: string): Promise> { + const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms)); + await sleep(1001); + var url = `${this.baseURL}?function=NEWS_SENTIMENT&apikey=${entity.getFieldValue("key")}`; if(entity.getFieldValue("ticker") !== null) { diff --git a/open-fin-al/src/Gateway/Data/RatioGateway/AlphaVantageRatioGateway.ts b/open-fin-al/src/Gateway/Data/RatioGateway/AlphaVantageRatioGateway.ts index 800c98c8..6c594983 100644 --- a/open-fin-al/src/Gateway/Data/RatioGateway/AlphaVantageRatioGateway.ts +++ b/open-fin-al/src/Gateway/Data/RatioGateway/AlphaVantageRatioGateway.ts @@ -27,6 +27,9 @@ export class AlphaVantageRatioGateway implements IDataGateway { } async read(entity: IEntity, action: string): Promise> { + const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms)); + await sleep(1001); + var url; if (action === "overview"){ url = this.getOverviewUrl(entity); diff --git a/open-fin-al/src/Gateway/Data/StockGateway/AlphaVantageStockGateway.ts b/open-fin-al/src/Gateway/Data/StockGateway/AlphaVantageStockGateway.ts index 9913bd4a..03773f75 100644 --- a/open-fin-al/src/Gateway/Data/StockGateway/AlphaVantageStockGateway.ts +++ b/open-fin-al/src/Gateway/Data/StockGateway/AlphaVantageStockGateway.ts @@ -28,6 +28,9 @@ export class AlphaVantageStockGateway implements IKeyedDataGateway { } async read(entity: IEntity, action: string): Promise> { + const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms)); + await sleep(1001); + try { var url; if (action === "lookup") { @@ -43,7 +46,7 @@ export class AlphaVantageStockGateway implements IKeyedDataGateway { } const urlObject = new URL(url); - + window.console.log(url); var endpointRequest = new JSONRequest(JSON.stringify({ request: { endpoint: { @@ -62,7 +65,8 @@ export class AlphaVantageStockGateway implements IKeyedDataGateway { endpoint.fillWithRequest(endpointRequest); const data = await window.exApi.fetch(this.baseURL, endpoint.toObject()); - + window.console.log(data); + if("Information" in data) { throw Error("The API key used for Alpha Vantage has reached its daily limit"); } diff --git a/open-fin-al/src/Interactor/InitializationInteractor.ts b/open-fin-al/src/Interactor/InitializationInteractor.ts index b13ad7f8..fbde7d03 100644 --- a/open-fin-al/src/Interactor/InitializationInteractor.ts +++ b/open-fin-al/src/Interactor/InitializationInteractor.ts @@ -12,6 +12,10 @@ import { SQLiteCompanyLookupGateway } from "../Gateway/Data/SQLite/SQLiteCompany import { SettingsInteractor } from "./SettingsInteractor"; import { SQLiteAssetGateway } from "../Gateway/Data/SQLite/SQLiteAssetGateway"; +declare global { + interface Window { slideshow: any; } +} + export class InitializationInteractor implements IInputBoundary { requestModel: IRequestModel; responseModel: IResponseModel; @@ -22,7 +26,21 @@ export class InitializationInteractor implements IInputBoundary { const configManager = new ConfigUpdater(); var configCreated; - if(action === "createConfig") { + if(action === "bundelSlideshows") { + try { + window.slideshow.verifyBundle(); + response = new JSONResponse(JSON.stringify({status: 200, ok: true})); + return response; + } catch(error) { + response = new JSONResponse(JSON.stringify({ + status: 500, + data: { + error: `An unknown erorr occurred while trying to bundel the slideshows.}` + }})); + + return response; + } + } else if(action === "createConfig") { try { //create the SQLite database const gateway = new SQLiteTableCreationGateway(); @@ -37,7 +55,7 @@ export class InitializationInteractor implements IInputBoundary { response = new JSONResponse(JSON.stringify({ status: 400, data: { - error: `The application configuration failed. Configurations created: ${configCreated}. Data tables created: ${tablesCreated}.}` + error: `The application configuration failed. Configurations created: ${configCreated}. Data tables created: ${tablesCreated}.` }})); } @@ -75,43 +93,6 @@ export class InitializationInteractor implements IInputBoundary { }})); return response; } - - //load the user table with the OS username - /* don't want to create user automatically during data initialization - TODO: remove user from settings area now that a seaparate user area exists - try { - const username = await window.config.getUsername(); - var firstName; - var lastName; - var email = window.vault.getSecret("Email") || null; - - if(window.config.exists()) { - const config = await window.config.load(); - firstName = config.UserSettings.FirstName; - lastName = config.UserSettings.LastName; - } - - var userInteractor = new UserInteractor(); - var userRequestObj = new JSONRequest(JSON.stringify({ - request: { - user: { - username: username, - firstName: firstName, - lastName: lastName, - email: email - } - } - })); - userResponse = await userInteractor.post(userRequestObj); - } catch(error) { - response = new JSONResponse(JSON.stringify({ - status: 500, - data: { - error: `An unkown error occured while created the application user.` - }})); - return response; - } - */ //return the response based on the outcomes of initialization // removed userReponse if(publicCompaniesResponse.response.ok && userResponse.response.ok) { diff --git a/open-fin-al/src/Interactor/SidecarInitializationInteractor.ts b/open-fin-al/src/Interactor/SidecarInitializationInteractor.ts new file mode 100644 index 00000000..bd864012 --- /dev/null +++ b/open-fin-al/src/Interactor/SidecarInitializationInteractor.ts @@ -0,0 +1,112 @@ +import {IInputBoundary} from "./IInputBoundary"; +import {IRequestModel} from "../Gateway/Request/IRequestModel"; +import {IResponseModel} from "../Gateway/Response/IResponseModel"; +import {JSONResponse} from "../Gateway/Response/JSONResponse"; +import { Neo4JGraphCreationGateway } from "../Gateway/Data/Neo4J/Neo4JGraphCreationGateway"; +import { graph } from "neo4j-driver"; + +export class SidecarInitializationInteractor implements IInputBoundary { + requestModel: IRequestModel; + responseModel: IResponseModel; + + async post(requestModel: IRequestModel, action:string=null): Promise { + var response; + const graphGateway = new Neo4JGraphCreationGateway(); + + if(action === "loadSidecar") { + try { + await graphGateway.connect(); + response = new JSONResponse(JSON.stringify({status: 200, ok: true})); + return response; + } catch(error) { + response = new JSONResponse(JSON.stringify({ + status: 500, + data: { + error: `An unknown erorr occurred while setting up the sidecar configurations.}` + }})); + + return response; + } + } else if (action === "initializeGraph") { + //load the table with company data after database init + try { + const graphCreated = await graphGateway.create(); + + if(graphCreated) { + response = new JSONResponse(JSON.stringify({status: 200, ok: true})); + } else { + response = new JSONResponse(JSON.stringify({ + status: 400, + data: { + error: `The sidecar configuration failed. Graph created: ${graphCreated}}` + }})); + } + + return response; + } catch(error) { + response = new JSONResponse(JSON.stringify({ + status: 500, + data: { + error: `An unkown error occured while creating the graph database.` + }})); + + return response; + } + } + } + + async get(requestModel: IRequestModel, action:string=null): Promise { + var response; + const graphGateway = new Neo4JGraphCreationGateway(); + + try { + if(action==="isLoaded") { + //check if Graph database has been created + const isConnected = await graphGateway.checkGraphConnected(); + + if(!isConnected) { + response = new JSONResponse(JSON.stringify({ + status: 404, + data: { + error: `The graph is not connected.` + }})); + return response; + } + + //return success if other tests passed + response = new JSONResponse(JSON.stringify({status: 200, ok: true})); + return response; + } else if(action==="isGraphInitialized") { + const graphExists = await graphGateway.checkGraphExists(); + + if(!graphExists) { + response = new JSONResponse(JSON.stringify({ + status: 404, + data: { + error: `The graph doesn't exist.` + }})); + return response; + } + + //return success if other tests passed + response = new JSONResponse(JSON.stringify({status: 200, ok: true})); + return response; + } + } catch(error) { + response = new JSONResponse(JSON.stringify({ + status: 500, + data: { + error: `An unkonwn error occured while checking the system initialization.` + }})); + return response; + } + } + + async put(requestModel: IRequestModel): Promise { + return this.post(requestModel); + } + + async delete(requestModel: IRequestModel): Promise { + return this.post(requestModel); + } +} \ No newline at end of file diff --git a/open-fin-al/src/Interactor/StockInteractor.ts b/open-fin-al/src/Interactor/StockInteractor.ts index 53335067..daa267be 100644 --- a/open-fin-al/src/Interactor/StockInteractor.ts +++ b/open-fin-al/src/Interactor/StockInteractor.ts @@ -96,10 +96,10 @@ export class StockInteractor implements IInputBoundary { //add the API key to the stock request object stock.setFieldValue("key", stockGateway.key); } - + //search for the requested information via the API gateway var results = await stockGateway.read(stock, requestModel.request.request.stock.action); - + window.console.log(results); if(results) { //convert the API gateway response to a JSON reponse object response = new JSONResponse(); diff --git a/open-fin-al/src/View/App.jsx b/open-fin-al/src/View/App.jsx index 71aa9269..8ef6d0fc 100644 --- a/open-fin-al/src/View/App.jsx +++ b/open-fin-al/src/View/App.jsx @@ -4,24 +4,30 @@ // Disclaimer of Liability // The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. -import React, { useState, createContext, useEffect } from "react"; +import React, { useState, createContext, useEffect, use } from "react"; // Imports for react pages and assets import AppLoaded from "./App/Loaded"; import { AppPreparing } from "./App/Preparing"; +import { AppSidecarPreparing } from "./App/SidecarPreparing"; import { AppConfiguring } from "./App/Configuring"; import { AuthContainer } from "./Auth/AuthContainer"; import { JSONRequest } from "../Gateway/Request/JSONRequest"; import { InitializationInteractor } from "../Interactor/InitializationInteractor"; +import { SidecarInitializationInteractor } from "../Interactor/SidecarInitializationInteractor"; +import { registerAllComponents } from "../hoc/registerComponents"; const DataContext = createContext(); function App(props) { const currentDate = new Date(); const [loading, setLoading] = useState(true); + const [sidecarLoading, setSidecarLoading] = useState(true); const [secureConnectionsValidated, setSecureConnectionsValidated] = useState(false); const [configured, setConfigured] = useState(false); + const [statusMessage, setStatusMessage] = useState(null); const [preparationError, setPreparationError] = useState(null); + const [sidecarPreparationError, setSidecarPreparationError] = useState(null); const [user, setUser] = useState(null); const [isAuthenticated, setIsAuthenticated] = useState(false); const [state, setState] = useState({ @@ -67,6 +73,10 @@ function App(props) { getDarkMode(); }, []); + useEffect(() => { + registerAllComponents(); + }, []); + // Check if user is already authenticated from previous session const checkAuthenticationState = () => { try { @@ -113,14 +123,18 @@ function App(props) { const executeDataInitialization = async() => { try { + setStatusMessage("Checking if system data is initialized..."); const interactor = new InitializationInteractor(); const requestObj = new JSONRequest(`{}`); - const response = await interactor.post(requestObj,"initializeData"); + const response = await interactor.post(requestObj,"initializeData"); + + let slideshowBundleReponse; if(response.response.ok) { setLoading(false); return true; } else { + setStatusMessage("Retreiving data resources for system use..."); //tables may have been deleted and need to be recreated const configurationResponse = await interactor.post(requestObj,"createConfig"); window.console.log(configurationResponse); @@ -140,6 +154,7 @@ function App(props) { const checkIfFullyInitialized = async () => { try { + setStatusMessage("Checking if the system is ready to start..."); //determine if application is fully configured and data initialized const interactor = new InitializationInteractor(); const requestObj = new JSONRequest(`{}`); @@ -149,19 +164,28 @@ function App(props) { setConfigured(true); if(secureConnectionsValidated) { - setLoading(false); checkAuthenticationState(); } else { + setStatusMessage("Updating security certificates..."); const interactor = new InitializationInteractor(); const requestObj = new JSONRequest(`{}`); const response = await interactor.post(requestObj,"refreshPinnedCertificates"); setSecureConnectionsValidated(true); + } + + setStatusMessage("Verifying learning modules are bundled..."); + const slideshowBundleReponse = await interactor.post(requestObj,"bundelSlideshows"); + + if(slideshowBundleReponse.response.ok) { setLoading(false); + } else { + throw new Error("The slideshow bundle did not configure properly"); } return true; } else { //check if the site is uninitialized but configured + setStatusMessage("Checking if the system is configured..."); const configurationResponse = await interactor.get(requestObj,"isConfigured"); if(configurationResponse.response.ok) { @@ -178,6 +202,7 @@ function App(props) { return false; } } else { + setStatusMessage("Creating initial configuration..."); await interactor.post(requestObj,"createConfig"); setConfigured(false); setLoading(true); @@ -191,31 +216,76 @@ function App(props) { } }; + const loadSidecar = async () => { + try { + const interactor = new SidecarInitializationInteractor(); + const requestObj = new JSONRequest(`{}`); + const response = await interactor.post(requestObj,"loadSidecar"); + + setStatusMessage("Starting the graph database..."); + + if(response.response.ok) { + const loadedResponse = await interactor.get(requestObj,"isLoaded"); + if(loadedResponse.response.ok) { + setStatusMessage("Graph database started. Checking if knowledge graph is set up..."); + const graphExistsResponse = await interactor.get(requestObj,"isGraphInitialized"); + + if(graphExistsResponse.response.ok) { + setStatusMessage("Knowledge graph is set up. Checking if system is fully initialized..."); + setSidecarLoading(false); + await checkIfFullyInitialized(); + return true; + } else { + setStatusMessage("Graph database started. Initializing knowledge graph..."); + const graphInitializedResponse = await interactor.post(requestObj,"initializeGraph"); + + if(graphInitializedResponse.response.ok) { + setSidecarLoading(false); + await checkIfFullyInitialized(); + return true; + } else { + throw new Error(); + } + } + } else { + throw new Error(); + } + } else { + throw new Error(); + } + } catch(error) { + setSidecarPreparationError("Failed to initilize the software database. Please contact the software administrator."); + window.console.log(error); + return false; + } + }; + useEffect( () => { - checkIfFullyInitialized(); + loadSidecar(); }, []); return ( - configured ? - ( - loading ? - - : - ( - !isAuthenticated ? - - : - - - - ) - ) - : - + sidecarLoading ? + + : + configured ? + ( loading ? + + : + ( !isAuthenticated ? + + : + + + + ) + ) + : + ); } diff --git a/open-fin-al/src/View/App/Loaded.jsx b/open-fin-al/src/View/App/Loaded.jsx index 5a73f1c8..0634c595 100644 --- a/open-fin-al/src/View/App/Loaded.jsx +++ b/open-fin-al/src/View/App/Loaded.jsx @@ -18,7 +18,7 @@ import { DataContext } from "../App"; import { AppLoadedLayout } from "./LoadedLayout" import Home from "../Home"; import Portfolio from "../Portfolio"; -import { Analysis } from "../Analysis"; +import RiskAnalysis from "../RiskAnalysis"; import BuyReport from "../BuyReport"; import { TimeSeries } from "../Stock"; import { News } from "../News"; @@ -114,7 +114,7 @@ class AppLoaded extends Component {
  • dashboard Dashboard
  • pie_chart Portfolio
  • attach_money Trade
  • -
  • assessment Risk Analysis
  • +
  • assessment Risk Analysis
  • compare Stock Comparison
  • timeline Forecast
  • article News
  • @@ -130,7 +130,7 @@ class AppLoaded extends Component { }> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/open-fin-al/src/View/App/Preparing.jsx b/open-fin-al/src/View/App/Preparing.jsx index da068fc4..f3944b10 100644 --- a/open-fin-al/src/View/App/Preparing.jsx +++ b/open-fin-al/src/View/App/Preparing.jsx @@ -19,7 +19,12 @@ export function AppPreparing(props) {

    {props.preparationError}

    ) : ( <> -

    Downloading data resources...

    + {props.statusMessage ? + ( +

    {props.statusMessage}

    + ) : ( +

    Starting system resources...

    + )}

    This may take a few minutes

    diff --git a/open-fin-al/src/View/App/SidecarPreparing.jsx b/open-fin-al/src/View/App/SidecarPreparing.jsx new file mode 100644 index 00000000..c2e5a86e --- /dev/null +++ b/open-fin-al/src/View/App/SidecarPreparing.jsx @@ -0,0 +1,36 @@ +// No Warranty +// This software is provided "as is" without any warranty of any kind, express or implied. This includes, but is not limited to, the warranties of merchantability, fitness for a particular purpose, and non-infringement. +// +// Disclaimer of Liability +// The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. + +import React, { useEffect } from "react"; + +//Imports for react pages and assets +import logo from "../../Asset/Image/logo-dark.png"; + +export function AppSidecarPreparing(props) { + return ( +
    +
    +
    Logo
    +
    + {props.sidecarPreparationError ? ( +

    {props.sidecarPreparationError}

    + ) : ( + <> + {props.statusMessage ? + ( +

    {props.statusMessage}

    + ) : ( +

    Starting system resources...

    + )} +

    This may take a few minutes

    +
    + + )} +
    +
    +
    + ); +} diff --git a/open-fin-al/src/View/Component/Learn/PowerPointComponent.tsx b/open-fin-al/src/View/Component/Learn/PowerPointComponent.tsx new file mode 100644 index 00000000..86c17be6 --- /dev/null +++ b/open-fin-al/src/View/Component/Learn/PowerPointComponent.tsx @@ -0,0 +1,40 @@ +import React, { useEffect, useRef, useState } from "react"; +import { withViewComponent, WithViewComponentProps } from "../../../hoc/withViewComponent"; +import { PowerPoint } from "../../LearningModule/Slideshow/PowerPoint.jsx"; + +interface PowerPointInnerProps extends WithViewComponentProps { + pptxPath: string; +} + +function PowerPointInner({ pptxPath, viewConfig }: PowerPointInnerProps) { + const containerRef = useRef(null); + const [availableWidth, setAvailableWidth] = useState(0); + + useEffect(() => { + const observer = new ResizeObserver(() => { + if (containerRef.current) { + setAvailableWidth(containerRef.current.offsetWidth); + } + }); + + if (containerRef.current) { + observer.observe(containerRef.current); + } + + return () => observer.disconnect(); + }, []); + + const multiplier = Math.floor(availableWidth / viewConfig.widthRatio); + const width = multiplier * viewConfig.widthRatio; + const height = multiplier * viewConfig.heightRatio; + + return ( +
    + {multiplier > 0 && ( + + )} +
    + ); +} + +export const PowerPointComponent = withViewComponent(PowerPointInner); \ No newline at end of file diff --git a/open-fin-al/src/View/Forecast.jsx b/open-fin-al/src/View/Forecast.jsx index 356f0148..887b073c 100644 --- a/open-fin-al/src/View/Forecast.jsx +++ b/open-fin-al/src/View/Forecast.jsx @@ -6,8 +6,8 @@ import React, { Component } from "react"; import { NavLink } from "react-router-dom"; -import binaryHeader from "../Asset/Image/binary_header.jpg"; -import aiHeader from "../Asset/Image/ai_header.jpg"; +import binaryHeader from "../Asset/Image/binary_header.png"; +import aiHeader from "../Asset/Image/ai_header.png"; import { HeaderContext } from "./App/LoadedLayout"; class Forecast extends Component { diff --git a/open-fin-al/src/View/ForecastFeature.jsx b/open-fin-al/src/View/ForecastFeature.jsx index 24bb8225..25d1a85f 100644 --- a/open-fin-al/src/View/ForecastFeature.jsx +++ b/open-fin-al/src/View/ForecastFeature.jsx @@ -1,11 +1,18 @@ -import React, { useContext, useEffect, useState } from "react"; +import React, { useContext, useEffect, useMemo, useState } from "react"; import { useLocation } from "react-router-dom"; +import { withViewComponent } from "../hoc/withViewComponent"; +import { ViewComponent } from "../types/ViewComponent"; import { TickerSearchBar } from "./Stock/TickerSearchBar"; -import { DataContext } from "./App"; import { RSIChart } from "./RSIChart"; import { MovingAvgChart } from "./MovingAVGChart"; import { ROCChart } from "./ROCChart"; +const WrappedTickerSearchBar = withViewComponent(TickerSearchBar); +const WrappedRSIChart = withViewComponent(RSIChart); +const WrappedMovingAvgChart = withViewComponent(MovingAvgChart); +const WrappedROCChart = withViewComponent(ROCChart); +import { DataContext } from "./App"; + function ForecastFeaturesPage(props) { const location = useLocation(); const { state, setState } = useContext(DataContext); @@ -26,14 +33,46 @@ function ForecastFeaturesPage(props) { setSelectedChart(event.target.value); }; - return ( + const tickerSearchConfig = useMemo(() => new ViewComponent({ + height: 50, width: 400, isContainer: false, resizable: false, + maintainAspectRatio: false, widthRatio: 1, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Ticker Search Bar", description: "Search bar for looking up stock ticker symbols", + tags: ["search", "ticker", "stock"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + + const rsiChartConfig = useMemo(() => new ViewComponent({ + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "RSI Chart", description: "Relative Strength Index chart", + tags: ["chart", "RSI", "indicator"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + + const movingAvgConfig = useMemo(() => new ViewComponent({ + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Moving Average Chart", description: "Moving average indicators chart", + tags: ["chart", "moving average", "indicator"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + + const rocChartConfig = useMemo(() => new ViewComponent({ + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "ROC Chart", description: "Rate of Change chart", + tags: ["chart", "ROC", "indicator"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + + return (

    Forecast Features

    {state ? ( <> - + {state.isLoading === true ? (

    Loading...

    ) : state.error ? ( @@ -52,11 +91,11 @@ function ForecastFeaturesPage(props) {
    {selectedChart === "RSIChart" ? ( - + ) : selectedChart === "MovingAvgChart" ? ( - + ) : ( - + )} ) : ( diff --git a/open-fin-al/src/View/Home.jsx b/open-fin-al/src/View/Home.jsx index 25cae006..cc6cdce7 100644 --- a/open-fin-al/src/View/Home.jsx +++ b/open-fin-al/src/View/Home.jsx @@ -8,13 +8,18 @@ import React, { Component } from 'react'; import profileIcon from "../Asset/Image/profile.jpg"; import { NewsInteractor } from "../Interactor/NewsInteractor"; import { JSONRequest } from "../Gateway/Request/JSONRequest"; +import { withViewComponent } from "../hoc/withViewComponent"; +import { ViewComponent } from "../types/ViewComponent"; import { NewsBrowser } from "./News/Browser"; +import { EconomicChart } from './Dashboard/EconomicChart'; + +const WrappedNewsBrowser = withViewComponent(NewsBrowser); +const WrappedEconomicChart = withViewComponent(EconomicChart); import {PortfolioTransactionInteractor} from "../Interactor/PortfolioTransactionInteractor"; import { StockInteractor } from "../Interactor/StockInteractor"; import { MarketStatusInteractor } from "../Interactor/MarketStatusInteractor"; import {EconomicIndicatorInteractor} from "../Interactor/EconomicIndicatorInteractor"; import { useNavigate, Link } from 'react-router-dom'; -import { EconomicChart } from './Dashboard/EconomicChart'; import { HeaderContext } from "./App/LoadedLayout"; const withNavigation = (Component) => { @@ -27,6 +32,22 @@ const withNavigation = (Component) => { class Home extends Component { static contextType = HeaderContext; + economicChartConfig = new ViewComponent({ + height: 200, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 2, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Economic Chart", description: "Displays macroeconomic data as a chart", + tags: ["chart", "economic", "macro"], minimumProficiencyRequirements: {}, requiresInternet: true, + }); + + newsBrowserConfig = new ViewComponent({ + height: 300, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "News Browser", description: "Browser for viewing and navigating news articles", + tags: ["news", "browser", "articles"], minimumProficiencyRequirements: {}, requiresInternet: true, + }); + formatter = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', @@ -308,9 +329,9 @@ class Home extends Component {
    {this.state.marketData ? - this.state.marketData.map((market) => { + this.state.marketData.map((market, index) => { return ( -

    +

    The {market.type} Market is:  {market.status.toUpperCase()}

    ) }) @@ -351,22 +372,25 @@ class Home extends Component {

    trending_up Total Value

    -

    {this.formatter.format(this.state.portfolioValue)} =0 ? {color:"green"}: {color:"red"}}>{this.calculatePercentChange()>0 ? "+" : ""}{this.percentFormatter.format(this.calculatePercentChange())}

    +

    + {this.formatter.format(this.state.portfolioValue)} + {(this.state.portfolioValue ? =0 ? {color:"green"}: {color:"red"}}> {this.calculatePercentChange()>0 ? "+" : ""}{this.percentFormatter.format(this.calculatePercentChange())} : )} +

    account_balance_wallet Total Buying Power

    -

    {this.formatter.format(this.state.buyingPower)} ({this.percentFormatter.format(this.state.buyingPower/this.state.portfolioValue)} cash)

    +

    {this.formatter.format(this.state.buyingPower)}

    {this.state.name ? this.state.name : "Economic Data"}

    - +
    {this.state.newsData ? - + : null } diff --git a/open-fin-al/src/View/Learn.jsx b/open-fin-al/src/View/Learn.jsx index 1e223022..a519e563 100644 --- a/open-fin-al/src/View/Learn.jsx +++ b/open-fin-al/src/View/Learn.jsx @@ -88,8 +88,6 @@ export function Learn() { } }; - window.console.log(window.electronApp.getAssetPath()); - return (
    { diff --git a/open-fin-al/src/View/LearningModule/LearningModuleDetails.jsx b/open-fin-al/src/View/LearningModule/LearningModuleDetails.jsx index 8ca97db2..14c47faa 100644 --- a/open-fin-al/src/View/LearningModule/LearningModuleDetails.jsx +++ b/open-fin-al/src/View/LearningModule/LearningModuleDetails.jsx @@ -45,12 +45,8 @@ export function LearningModuleDetails(props) { const handleStartModule = async () => { try { - // get base asset path from Electron (async) - const assetPath = await window.electronApp.getAssetPath(); - - // TODO: handle different OS path separators - const filePath = `${assetPath}\\${location.state.fileName}`; - + const filePath = await window.slideshow.getPath(location.state.fileName); + window.console.log(filePath); // navigate to the learningModulePage route with the full path navigate("/learningModulePage", { state: { diff --git a/open-fin-al/src/View/LearningModule/LearningModulePage.jsx b/open-fin-al/src/View/LearningModule/LearningModulePage.jsx index 49ec1489..04d3f387 100644 --- a/open-fin-al/src/View/LearningModule/LearningModulePage.jsx +++ b/open-fin-al/src/View/LearningModule/LearningModulePage.jsx @@ -4,21 +4,31 @@ // Disclaimer of Liability // The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. -import React from "react"; +import React, { useMemo } from "react"; import { useLocation } from "react-router-dom"; -import { PowerPoint } from "./Slideshow/PowerPoint"; +import { PowerPointComponent } from "../Component/Learn/PowerPointComponent"; +import { ViewComponent } from "../../types/ViewComponent"; export function LearningModulePage(props) { const location = useLocation(); const fileName = location.state.fileName; window.console.log(location.state); - return ( + + const pptxConfig = useMemo(() => new ViewComponent({ + height: 450, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "PowerPoint Viewer", description: "Displays a PowerPoint slideshow", + tags: ["learn", "slideshow", "powerpoint"], minimumProficiencyRequirements: {}, requiresInternet: false, + }), []); + + return (
    - +
    ); } diff --git a/open-fin-al/src/View/LearningModule/Slideshow/PowerPoint.jsx b/open-fin-al/src/View/LearningModule/Slideshow/PowerPoint.jsx index 92c50b48..609e7392 100644 --- a/open-fin-al/src/View/LearningModule/Slideshow/PowerPoint.jsx +++ b/open-fin-al/src/View/LearningModule/Slideshow/PowerPoint.jsx @@ -12,14 +12,14 @@ function PowerPoint(props) { const navigate = useNavigate(); const [isDisabled, setIsDisabled] = useState(false); - const containerRef = useRef(null); + const slideshowContainerRef = useRef(null); const viewerRef = useRef(null); const [currentSlide, setCurrentSlide] = useState(0); const [totalSlides, setTotalSlides] = useState(0); + const naturalSizeRef = useRef({ width: 0, height: 0 }); const pptxPath = props.pptxPath; - window.console.log(pptxPath); //navigate to the learn base page @@ -31,15 +31,70 @@ function PowerPoint(props) { // Initialize pptx-preview // ----------------------------- useEffect(() => { - if (!containerRef.current) return; + window.console.log(props.width, props.height); + if (!slideshowContainerRef.current) return; + if (!viewerRef.current) { - viewerRef.current = initPptxPreview(containerRef.current, { - width: 900, - height: 506, + viewerRef.current = initPptxPreview(slideshowContainerRef.current, { + width: props.width, + height: props.height, }); + + naturalSizeRef.current = { + width: props.width, + height: props.height, + }; } }, []); + useEffect(() => { + window.console.log(props.width, props.height); + const container = slideshowContainerRef.current; + /* + // Grab *one* slide's inner content (canvas/svg/img) + const inner = container.querySelector( + ".pptx-preview-slide-wrapper > *" + ); + if (!inner) return;*/ + + const { width: baseW, height: baseH } = naturalSizeRef.current; + if (!baseW || !baseH) return; + + /*const rect = inner.getBoundingClientRect(); + if (!rect.width || !rect.height) return;*/ + + const containerWidth = props.width; + const containerHeight = props.height; + + const scale = Math.min( + containerWidth / baseW, + containerHeight / baseH + ); + + window.console.log("Calculated scale:", scale); + + // Expose scale as a CSS variable on the container + //container.style.setProperty("--pptx-scale", String(scale)); + slideshowContainerRef.current.style.setProperty( + "--pptx-scale", + String(scale) + ); + + slideshowContainerRef.current.style.width = `${containerWidth}px`; + slideshowContainerRef.current.style.height = `${containerHeight}px`; + slideshowContainerRef.current.style.position = "relative"; + + const inner = container.querySelector( + ".pptx-preview-wrapper" + ); + if (!inner) return; + + inner.style.position = 'absolute'; + inner.style.left = `0`; + inner.style.overflow = `hidden`; + + }, [props.width, props.height]); + useEffect(() => { if (!viewerRef.current || !pptxPath) return; @@ -59,8 +114,8 @@ function PowerPoint(props) { await viewerRef.current.preview(arrayBuffer); - if (containerRef.current) { - const slides = containerRef.current.querySelectorAll( + if (slideshowContainerRef.current) { + const slides = slideshowContainerRef.current.querySelectorAll( ".pptx-preview-slide-wrapper" ); setTotalSlides(slides.length); @@ -77,9 +132,9 @@ function PowerPoint(props) { }, [pptxPath]); const showSlide = (index) => { - if (!containerRef.current) return; + if (!slideshowContainerRef.current) return; - const slides = containerRef.current.querySelectorAll( + const slides = slideshowContainerRef.current.querySelectorAll( ".pptx-preview-slide-wrapper" ); @@ -109,11 +164,11 @@ function PowerPoint(props) { {/* Fixed-Size Slide Window */}
    {/* pptx-preview will render into this div */} -
    { setHeader({ title: "Investment News", - icon: "article", + icon: "article", }); }, [setHeader]); - + //ensure that the state changes useEffect(() => { setState({ @@ -40,12 +45,28 @@ function NewsPage(props) { setState(newState); }; + const newsSearchBarConfig = useMemo(() => new ViewComponent({ + height: 50, width: 400, isContainer: false, resizable: false, + maintainAspectRatio: false, widthRatio: 1, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "News Search Bar", description: "Search bar for finding news articles", + tags: ["news", "search"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + + const newsListingConfig = useMemo(() => new ViewComponent({ + height: 120, width: 600, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "News Listing", description: "List view of news articles", + tags: ["news", "listing"], minimumProficiencyRequirements: {}, requiresInternet: true, + }), []); + return ( -
    +
    {state ? ( <> - + {state.isLoading ? (

    Loading...

    ) : @@ -56,7 +77,7 @@ function NewsPage(props) {

    Data Source: {state.newsSource}

    {state.newsData && state.newsData.response.results[0] ? state.newsData.response.results[0]["data"].map((listing, index) => ( - + )) : null } @@ -76,4 +97,4 @@ function NewsPage(props) { // In case hooks are needed for this class. Can remove later if not necessary export function News(props) { return -}; \ No newline at end of file +}; diff --git a/open-fin-al/src/View/News/Browser.jsx b/open-fin-al/src/View/News/Browser.jsx index 2b3bbe51..0e01dbf5 100644 --- a/open-fin-al/src/View/News/Browser.jsx +++ b/open-fin-al/src/View/News/Browser.jsx @@ -5,6 +5,7 @@ // The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. import React from "react"; +import defaultThumbnail from "../../Asset/Image/thumbnail_unavailable.png"; function NewsBrowser({ listingData, handlePrevious, handleNext }) { // Format date and time from listingData @@ -19,7 +20,12 @@ function NewsBrowser({ listingData, handlePrevious, handleNext }) { return (
    - Thumbnail + Thumbnail { + // prevent infinite loop if fallback is missing + e.currentTarget.onerror = null; + e.currentTarget.src = defaultThumbnail; + }} />

    - Thumbnail + Thumbnail { + // prevent infinite loop if fallback is missing + e.currentTarget.onerror = null; + e.currentTarget.src = defaultThumbnail; + }} />

    { class Portfolio extends Component { static contextType = HeaderContext; + + portfolioCreationConfig = new ViewComponent({ + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Portfolio Creation", description: "Interface for creating and managing investment portfolios", + tags: ["portfolio", "creation", "investment"], minimumProficiencyRequirements: {}, requiresInternet: true, + }); async componentDidMount() { window.console.log("Portfolio context in componentDidMount:", this.context); @@ -85,13 +97,19 @@ class Portfolio extends Component { await this.fetchPortfolios(); const cashId = await this.getCashId(); + await this.getPortfolioData(); + } + + async getPortfolioData() { + window.console.log("Portfolio id:", this.state.currentPortfolio); + // Only fetch portfolio data if a portfolio is selected if(this.state.currentPortfolio) { await this.getPortfolioValue(); await this.getPortfolioChartData(); - if(cashId) { - await this.getBuyingPower(cashId); + if(this.state.cashId) { + await this.getBuyingPower(this.state.cashId); } } } @@ -186,10 +204,18 @@ class Portfolio extends Component { } async changeCurrentPortfolio(portfolioId, portfolioName) { - this.setState({currentPortfolio: portfolioId, portfolioName: portfolioName}); - await this.getBuyingPower(null, portfolioId); - await this.getPortfolioValue(portfolioId); - await this.getPortfolioChartData(portfolioId); + window.console.log("Portfolio id changed to:", portfolioId); + this.setState({ + currentPortfolio: portfolioId, + portfolioName: portfolioName, + portfolioValue: 0, + assetData: [], + chartData: [], + buyingPower: 0, + buyingPowerLoaded: false, + }); + await this.sleep(1000); // allow time for state to set + await this.getPortfolioData(); } async getCashId() { @@ -433,7 +459,7 @@ class Portfolio extends Component { )}

    - {this.state.buyingPowerLoaded && + {this.state.buyingPowerLoaded ? <>
    @@ -461,6 +487,13 @@ class Portfolio extends Component {

    {this.formatter.format(this.state.buyingPower)}

    + + : +
    +
    Retrieving portfolio data...
    +
    + } + <>

    Stock Assets

    @@ -490,11 +523,11 @@ class Portfolio extends Component {
    - } +
    : <> - { } + { } }

    diff --git a/open-fin-al/src/View/RiskAnalysis.jsx b/open-fin-al/src/View/RiskAnalysis.jsx new file mode 100644 index 00000000..409225ed --- /dev/null +++ b/open-fin-al/src/View/RiskAnalysis.jsx @@ -0,0 +1,1100 @@ +// No Warranty +// This software is provided "as is" without any warranty of any kind, express or implied. This includes, but is not limited to, the warranties of merchantability, fitness for a particular purpose, and non-infringement. +// +// Disclaimer of Liability +// The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. + +import React, { Component } from "react"; +import { withViewComponent } from "../hoc/withViewComponent"; +import { ViewComponent } from "../types/ViewComponent"; +import { PortfolioCreation } from "./Portfolio/Creation"; + +const WrappedPortfolioCreation = withViewComponent(PortfolioCreation); +import { PortfolioInteractor } from "../Interactor/PortfolioInteractor"; +import {PortfolioTransactionInteractor} from "../Interactor/PortfolioTransactionInteractor"; +import { StockInteractor } from "../Interactor/StockInteractor"; +import {JSONRequest} from "../Gateway/Request/JSONRequest"; +import { HeaderContext } from "./App/LoadedLayout"; + +import { Popover } from "react-tiny-popover"; +import { PieChart, Pie, Sector, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'; // For adding charts + +const formatter = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); + +const renderActiveShape = (props) => { + window.console.log(props); + const RADIAN = Math.PI / 180; + const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value } = props; + const sin = Math.sin(-RADIAN * midAngle); + const cos = Math.cos(-RADIAN * midAngle); + const sx = cx + (outerRadius + 10) * cos; + const sy = cy + (outerRadius + 10) * sin; + const mx = cx + (outerRadius + 30) * cos; + const my = cy + (outerRadius + 30) * sin; + const ex = mx + (cos >= 0 ? 1 : -1) * 22; + const ey = my; + const textAnchor = cos >= 0 ? 'start' : 'end'; + window.console.log(payload); + return ( + + + {payload.name} + + + + + + = 0 ? 1 : -1) * 12} y={ey} textAnchor={textAnchor} fill="#333">{`${formatter.format(value)}`} + = 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill="#999"> + {`(${(percent * 100).toFixed(2)}%)`} + + + ); +}; + +class RiskAnalysis extends Component { + static contextType = HeaderContext; + + portfolioCreationConfig = new ViewComponent({ + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Portfolio Creation", description: "Interface for creating and managing investment portfolios", + tags: ["portfolio", "creation", "investment"], minimumProficiencyRequirements: {}, requiresInternet: true, + }); + + async componentDidMount() { + window.console.log("Portfolio context in componentDidMount:", this.context); + const { setHeader } = this.context || {}; + + if (setHeader) { + setHeader({ + title: "Risk Analysis", + icon: "assessment", + }); + } + + await this.fetchPortfolios(); + const cashId = await this.getCashId(); + + await this.getPortfolioData(); + } + + async getPortfolioData() { + window.console.log("Portfolio id:", this.state.currentPortfolio); + + // Only fetch portfolio data if a portfolio is selected + if(this.state.currentPortfolio) { + await this.getPortfolioValue(); + await this.getPortfolioChartData(); + + if(this.state.cashId) { + await this.getBuyingPower(this.state.cashId); + } + + await this.fetchDailyHistoricalReturnsData(); + } + } + + formatter = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); + + percentFormatter = new Intl.NumberFormat('en-US', { + style: 'percent', + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); + + constructor(props) { + super(props); + this.state = { + createPortfolio: true, + currentPortfolio: null, + portfolios: [], + isModalOpen: false, + depositAmount: 0, + cashId: null, + depositMessage: null, + portfolioValue: 0, + assetData: [], + chartData: [], + assetReturnsTimeSeries: {}, + assetReturnsDates: [], + oneYearRisk: {}, + twoYearRisk: {}, + threeYearRisk: {}, + buyingPower: 0, + buyingPowerLoaded: false, + activeIndex: 0, + portfolioName: null, + hoveredInfo: null + }; + + //Bind methods for element events + this.openModal = this.openModal.bind(this); + this.getBuyingPower = this.getBuyingPower.bind(this); + this.onPieEnter = this.onPieEnter.bind(this); + this.handleInfoHover = this.handleInfoHover.bind(this); + this.handleInfoLeave = this.handleInfoLeave.bind(this); + } + + async openModal() { + this.setState({ + depositMessage: null, + isModalOpen: true + }); + } + handleInfoHover(metric) { + this.setState({hoveredInfo: metric}); + } + + handleInfoLeave() { + this.setState({hoveredInfo: null}); + } + + async fetchPortfolios() { + // Get user from localStorage (auth system) + const savedUser = localStorage.getItem('openfinAL_user'); + if (!savedUser) { + console.error('No user found in session'); + return; + } + + const userData = JSON.parse(savedUser); + if (!userData.id) { + console.error('Invalid user session'); + return; + } + + const interactor = new PortfolioInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + portfolio: { + userId: userData.id + } + } + })); + + const response = await interactor.get(requestObj); + + var defaultPortfolio = null; + var defaultPortfolioName = null; + for(var portfolio of response.response?.results) { + if(portfolio.isDefault) { + defaultPortfolio = portfolio.id; + defaultPortfolioName = portfolio.name; + this.setState({createPortfolio: false}); + break; + } + } + + this.setState({ + currentPortfolio: defaultPortfolio, + portfolioName: defaultPortfolioName, + portfolios: response.response?.results || [] + }); + } + + async fetchDailyHistoricalReturnsData() { + if(!this.state.currentPortfolio || !this.state.assetData) { + return; + } + + let dates = []; + const assetReturnTimeseries = {}; + + for(var asset of this.state.assetData) { + window.console.log(asset); + if(asset.type==="Stock") { + window.console.log(asset["symbol"]); + const interactor = new StockInteractor(); + const request = new JSONRequest(JSON.stringify({ + request: { + stock: { + action: "interday", + ticker: asset["symbol"], + interval: "5Y" + } + } + })); + + const response = await interactor.get(request); + + if(response?.response?.ok) { + let series = []; + let recordDates = false; + + if(dates.length < response.response.results[0].data.length) { + recordDates = true; + dates = []; + } + + for(var i in response.response.results[0].data) { + var datum = response.response.results[0].data[i]; + var datumMinus1 = i > 0 ? response.response.results[0].data[i-1] : null; + + // don't keep item 0 because there is no t-1 data point for item 0 + if(recordDates && i > 0) { + dates.push(datum.date); + } + + if(i > 0) { + let returnValue = this.calculateReturn(datum.price, datumMinus1.price); + series.push(returnValue); + } + } + + assetReturnTimeseries[asset.symbol] = series; + } + } + } + + window.console.log(assetReturnTimeseries); + window.console.log(dates); + + if (Object.keys(assetReturnTimeseries).length === 0 || dates.length === 0) { + window.console.log("No return data available to compute risk."); + return; + } + + const df = this.returnsToDataFrame(assetReturnTimeseries, dates); + const weights = this.computeWeights(this.state.assetData, this.state.portfolioValue); + + const oneYear = this.computeRiskBundle(df, weights, 252); + const twoYear = this.computeRiskBundle(df, weights, 504); + const threeYear = this.computeRiskBundle(df, weights, 756); + + this.setState({ + oneYearRisk: oneYear, + twoYearRisk: twoYear, + threeYearRisk: threeYear + }); + + window.console.log(oneYear, twoYear, threeYear); + } + + computeRiskBundle(dfAll, weightsByTicker, windowDays) { + const tickers = Object.keys(weightsByTicker); + + const df = this.sliceLookback(dfAll, tickers, windowDays); + + const cov = this.covarianceDaily(df, tickers); + const corr = this.correlationFromCov(cov); + const { volDaily, volAnnual } = this.portfolioVolFromCov(cov, weightsByTicker); + + const { rows } = this.riskContributionsFromCov(cov, weightsByTicker); + + // annualize MCR/RC consistently if you want annual outputs: + // multiply mcr and rc by sqrt(252) (because they are volatility-like units) + const annualFactor = Math.sqrt(windowDays); + const rowsAnnual = rows.map(r => ({ + ...r, + mcrAnnual: r.mcr * annualFactor, + rcAnnual: r.nrc * annualFactor + })); + + // Max Drawdown (computed from portfolio daily returns in the same lookback window) + const rp = this.portfolioReturnsSeries(df, weightsByTicker, tickers); + const maxDrawdown = this.maxDrawdownFromReturns(rp); + const { var: var95, cvar: cvar95 } = this.varCvarFromReturns(rp, 0.95); + + return { cov, corr, volDaily, volAnnual, maxDrawdown, var95, cvar95, rows: rowsAnnual }; + } + + computeWeights(assetData, portfolioValue) { + const w = {}; + for (const a of assetData) { + if (a.type === "Stock" && a.symbol && a.currentValue != null) { + w[a.symbol] = a.currentValue / portfolioValue; + } + } + return w; + } + + calculateReturn(priceT, priceTMinus1) { + return (priceT - priceTMinus1) / priceTMinus1; + } + + // alpha=0.95 => 95% VaR/CVaR (worst 5% tail) + varCvarFromReturns(rp, alpha = 0.95) { + const clean = rp.filter(x => Number.isFinite(x)).slice().sort((a, b) => a - b); // ascending + if (clean.length < 10) return { var: null, cvar: null }; + + const tailProb = 1 - alpha; // 0.05 + const idx = Math.max(0, Math.floor(tailProb * clean.length)); + + const varReturn = clean[idx]; // typically negative + const tail = clean.slice(0, idx + 1); // worst tail + const cvarReturn = tail.reduce((s, x) => s + x, 0) / tail.length; + + // Return as positive loss magnitudes (more intuitive for UI) + return { var: -varReturn, cvar: -cvarReturn }; + } + + returnsToDataFrame(returnsByTicker, dates) { + window.console.log(returnsByTicker, dates); + + const dfd = window.dfd; + + const df = new dfd.DataFrame(returnsByTicker); + + // Attach dates (as a normal column; safest across Danfo versions) + df.addColumn("date", dates, { inplace: true }); + + // Reorder to put date first (optional) + const cols = ["date", ...Object.keys(returnsByTicker)]; + window.console.log(df.loc({ columns: cols })); + return df.loc({ columns: cols }); + } + + covarianceDaily(df, tickers) { + const dfd = window.dfd; + + // r: DataFrame with only return columns + const r = df.loc({ columns: tickers }); + + // values: rows x cols (T x N) + const Xraw = r.values; + + // Convert to numeric and drop any rows with non-finite values (NaN/undefined) + const X = []; + for (let i = 0; i < Xraw.length; i++) { + const row = Xraw[i].map(v => Number(v)); + if (row.every(v => Number.isFinite(v))) X.push(row); + } + + const T = X.length; + const N = tickers.length; + + if (T < 2) { + // Not enough data; return zeros + const zero = Array.from({ length: N }, () => Array(N).fill(0)); + return new dfd.DataFrame(zero, { columns: tickers, index: tickers }); + } + + // Column means + const means = Array(N).fill(0); + for (let t = 0; t < T; t++) { + for (let j = 0; j < N; j++) means[j] += X[t][j]; + } + for (let j = 0; j < N; j++) means[j] /= T; + + // Covariance (sample covariance, divide by T-1) + const cov = Array.from({ length: N }, () => Array(N).fill(0)); + for (let t = 0; t < T; t++) { + for (let i = 0; i < N; i++) { + const di = X[t][i] - means[i]; + for (let j = 0; j < N; j++) { + cov[i][j] += di * (X[t][j] - means[j]); + } + } + } + const denom = T - 1; + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) cov[i][j] /= denom; + } + + return new dfd.DataFrame(cov, { columns: tickers, index: tickers }); + } + + correlationFromCov(covDf) { + const dfd = window.dfd; + + const cov = covDf.values; // NxN + const cols = covDf.columns; // tickers + const N = cols.length; + + // std devs = sqrt(diagonal) + const std = new Array(N).fill(0); + for (let i = 0; i < N; i++) { + const v = Number(cov[i][i]); + std[i] = v > 0 ? Math.sqrt(v) : 0; + } + + const corr = Array.from({ length: N }, () => Array(N).fill(0)); + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + const denom = std[i] * std[j]; + corr[i][j] = denom ? cov[i][j] / denom : 0; + } + } + + return new dfd.DataFrame(corr, { columns: cols, index: cols }); + } + + portfolioVolFromCov(covDf, weightsByTicker, tradingDays = 252) { + const tickers = covDf.columns; + const cov = covDf.values; // 2D array + + // aligned weight vector + const w = tickers.map(t => weightsByTicker[t] ?? 0); + + // variance = wᵀ Σ w + let varP = 0; + for (let i = 0; i < tickers.length; i++) { + for (let j = 0; j < tickers.length; j++) { + varP += w[i] * cov[i][j] * w[j]; + } + } + + const volDaily = Math.sqrt(varP); + const volAnnual = volDaily * Math.sqrt(tradingDays); + + return { varP, volDaily, volAnnual }; + } + + riskContributionsFromCov(covDf, weightsByTicker) { + const tickers = covDf.columns; + const cov = covDf.values; + + const w = tickers.map(t => weightsByTicker[t] ?? 0); + + // compute sigma_p + let varP = 0; + for (let i = 0; i < tickers.length; i++) { + for (let j = 0; j < tickers.length; j++) { + varP += w[i] * cov[i][j] * w[j]; + } + } + const sigmaP = Math.sqrt(varP); + if (sigmaP === 0) { + return { sigmaP: 0, rows: tickers.map(t => ({ ticker: t, weight: weightsByTicker[t] ?? 0, mcr: 0, rc: 0, pctRc: 0 })) }; + } + + // compute Σw + const sigmaW = new Array(tickers.length).fill(0); + for (let i = 0; i < tickers.length; i++) { + for (let j = 0; j < tickers.length; j++) { + sigmaW[i] += cov[i][j] * w[j]; + } + } + + // MCR, RC, %RC + const rows = tickers.map((t, i) => { + const mcr = sigmaW[i] / sigmaP; + const rc = w[i] * mcr; + const pctRc = rc / sigmaP; + return { ticker: t, weight: w[i], mcr, rc, pctRc }; + }); + + return { sigmaP, rows }; + } + + sliceLookback(df, tickers, windowDays) { + const r = df.loc({ columns: ["date", ...tickers] }); + + const n = r.shape[0]; + const start = Math.max(0, n - windowDays); + + return r.iloc({ rows: [`${start}:`] }); + } + + portfolioReturnsSeries(df, weightsByTicker, tickers) { + // df contains date + tickers columns; returns are decimals + const r = df.loc({ columns: tickers }); + const Xraw = r.values; // rows x cols + const w = tickers.map(t => Number(weightsByTicker[t] ?? 0)); + + // build portfolio daily returns rp[t] = sum_i w_i * r_{t,i} + const rp = new Array(Xraw.length).fill(0); + + for (let t = 0; t < Xraw.length; t++) { + let sum = 0; + for (let j = 0; j < tickers.length; j++) { + const v = Number(Xraw[t][j]); + // treat non-finite as 0 to avoid poisoning the series + sum += (Number.isFinite(v) ? v : 0) * w[j]; + } + rp[t] = sum; + } + return rp; + } + + maxDrawdownFromReturns(portfolioReturns) { + // returns decimal negative number (e.g., -0.28 for -28%) + let wealth = 1.0; + let peak = 1.0; + let maxDD = 0; // most negative drawdown + + for (const r of portfolioReturns) { + const rr = Number(r); + wealth *= (1 + (Number.isFinite(rr) ? rr : 0)); + if (wealth > peak) peak = wealth; + const dd = (wealth / peak) - 1; + if (dd < maxDD) maxDD = dd; + } + + return maxDD; + } + + async changeCurrentPortfolio(portfolioId, portfolioName) { + this.setState({ + currentPortfolio: portfolioId, + portfolioName: portfolioName, + portfolioValue: 0, + assetData: [], + chartData: [], + assetReturnsTimeSeries: {}, + assetReturnsDates: [], + oneYearRisk: {}, + twoYearRisk: {}, + threeYearRisk: {}, + buyingPower: 0, + buyingPowerLoaded: false, + }); + await this.sleep(1000); // allow time for state to set + await this.getPortfolioData(); + } + + async getCashId() { + const interactor = new PortfolioInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + action: "getCashId" + } + })); + + const response = await interactor.get(requestObj); + + if(response?.response?.ok) { + this.setState({cashId: response.response.results[0].id}); + return response.response.results[0].id; + } + return null; + } + + async getBuyingPower(cashId=null, portfolioId=null) { + try { + if(!cashId) { + cashId = this.state.cashId; + } + + if(!portfolioId) { + portfolioId = this.state.currentPortfolio; + } + + const interactor = new PortfolioTransactionInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + action: "getBuyingPower", + transaction: { + portfolioId: portfolioId, + entry: { + assetId: cashId + } + } + + } + })); + + const response = await interactor.get(requestObj); + if(response && response.response && response.response.ok && response.response.results && response.response.results[0]) { + this.setState({buyingPowerLoaded: true, buyingPower: response.response.results[0].buyingPower}); + return true; + } else { + console.error('Buying power API response error:', response); + this.setState({buyingPowerLoaded: true, buyingPower: 0}); + return false; + } + } catch (error) { + console.error('Error fetching buying power:', error); + this.setState({buyingPowerLoaded: true, buyingPower: 0}); + return false; + } + } + + async getPortfolioValue(portfolioId=null) { + if(!portfolioId) { + portfolioId = this.state.currentPortfolio; + } + + const interactor = new PortfolioTransactionInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + action: "getPortfolioValue", + transaction: { + portfolioId: portfolioId + } + + } + })); + + const response = await interactor.get(requestObj); + + if(response?.response?.ok) { + var portfolioValue = 0; + for(var i in response.response.results) { + var asset = response.response.results[i]; + + if(asset.type==="Stock") { + const interactor = new StockInteractor(); + const quoteRequestObj = new JSONRequest(JSON.stringify({ + request: { + stock: { + action: "quote", + ticker: asset["symbol"] + } + } + })); + + const quoteResponse = await interactor.get(quoteRequestObj); + + if(quoteResponse?.response?.ok && quoteResponse.response.results[0]?.quotePrice) { + response.response.results[i]["quotePrice"] = quoteResponse.response.results[0].quotePrice; + response.response.results[i]["currentValue"] = asset.quantity * quoteResponse.response.results[0].quotePrice; + portfolioValue += asset.quantity * quoteResponse.response.results[0].quotePrice; + } else { + // If quote not available, use the original asset value + response.response.results[i]["quotePrice"] = asset.assetValue / asset.quantity; + response.response.results[i]["currentValue"] = asset.assetValue; + portfolioValue += asset.assetValue; + } + } else { + portfolioValue += asset.assetValue; + } + } + + this.setState({assetData: response.response.results}); + this.setState({portfolioValue: portfolioValue}); + return true; + } else { + return false; + } + } + + async getPortfolioChartData(portfolioId=null) { + if(!portfolioId) { + portfolioId = this.state.currentPortfolio; + } + + const interactor = new PortfolioTransactionInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + action: "getPortfolioValue", + transaction: { + portfolioId: portfolioId + } + + } + })); + + const response = await interactor.get(requestObj); + + if(response?.response?.ok) { + var chartData = []; + for(var asset of response.response.results) { + var assetObj = {}; + assetObj.name = asset.symbol; + assetObj.value = asset.assetValue; + chartData.push(assetObj); + } + + this.setState({chartData: chartData}); + return true; + } else { + return false; + } + } + + onPieEnter(_, index) { + this.setState({ activeIndex: index }); + } + + async sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + corrDfToHeatmapCells(corrDf) { + const tickers = corrDf.columns; + const M = corrDf.values; + + const cells = []; + for (let r = 0; r < tickers.length; r++) { + for (let c = 0; c < tickers.length; c++) { + cells.push({ + row: tickers[r], + col: tickers[c], + value: Number(M[r][c]) + }); + } + } + return { tickers, cells }; + } + + render() { + return ( +
    +
    + +
    + + {!this.state.createPortfolio && this.state.currentPortfolio ? +
    + {/* Portfolio Value and Buying Power Section */} + {this.state.buyingPowerLoaded ? + <> +
    +
    + + + +
    +
    +
    +

    Portfolio Value

    +

    {this.formatter.format(this.state.portfolioValue)}

    +
    +
    +
    + + : +
    +
    Retrieving portfolio data...
    +
    + } + <> +

    + { + this.state.threeYearRisk?.var95 ? "Portfolio Risk" : + + (this.state.buyingPowerLoaded ? + <> + +
    + Calculating Portfolio Risk...
    +
    + + : "Portfolio Risk") + } +

    +
    +
    + + Risk horizon is the length of time over which risk metrics are calculated. Short-term horizons capture short-term risks, while longer-term horizons capture longer-term risks. +
    }> + + +
    +
    + + Daily Volatility is a measure of how much a portfolio’s returns typically move up or down in a single day. For example, a daily volatility of 1% means that on a typical day, the portfolio’s value moves up or down by about 1%. +
    }> + + +
    +
    + + Annual Volatility estimates how much a portfolio’s returns are expected to fluctuate over a full year. For example, an annual volatility of 16% means that over a full year, the portfolio’s return typically varies up or down by about 16%. +
    }> + + +
    +
    + + Maximum Drawdown measures the biggest loss an investment has had from its highest point to its lowest point before recovering to a new high point. For example, a maximum drawdown of 15% means that at some point during the period, the portfolio fell 15% from its highest value to its lowest value before recovering. +
    }> + + +
    +
    + + Value at Risk (VaR), estimates the worst expected loss over a given period 95% of the time. For example, a VaR(95) of 2% means that on 95 out of 100 days, losses should not exceed 2%. +
    }> + + +
    +
    + + Conditional Value at Risk (CVaR) measures the average loss on the worst 5% of days, focusing on how bad losses are when things go wrong. A CVaR(95%) of 4% means that on the worst 5 out of 100 days, the portfolio loses about 4% on average. +
    }> + + +
    +
    + {[ + { label: "1-Year", risk: this.state.oneYearRisk }, + { label: "2-Year", risk: this.state.twoYearRisk }, + { label: "3-Year", risk: this.state.threeYearRisk }, + ].map(({ label, risk }) => ( + ( this.state.threeYearRisk?.cvar95 && +
    +
    {label}
    +
    + {risk?.volDaily != null ? this.percentFormatter.format(risk.volDaily) : "Calculating..."} +
    +
    + {risk?.volAnnual != null ? this.percentFormatter.format(risk.volAnnual) : "Calculating..."} +
    +
    + {risk?.maxDrawdown != null ? this.percentFormatter.format(Math.abs(risk.maxDrawdown)) : "Calculating..."} +
    +
    + {risk?.var95 != null ? this.percentFormatter.format(risk.var95) : "Calculating..."} +
    +
    + {risk?.cvar95 != null ? this.percentFormatter.format(risk.cvar95) : "Calculating..."} +
    +
    + ) + ))} +
    +

    Contributions to Risk (2-Year Time Horizon)

    +
    +
    Symbol
    +
    + + The portfolio weight of an asset is the percentage of the portfolio’s total value that is invested in the specific asset. For example, if a stock has a portfolio weight of 25%, that means 25% of the total portfolio value is invested in that stock. +
    }> + + +
    +
    + + Marginal Contribution to Risk (MCR) measures how much an individual asset adds to the portfolio’s overall risk if its weight increases slightly. For example, if a stock has an MCR of 1.5%, increasing that stock’s weight slightly would increase the portfolio’s total risk by about 1.5%, not considering its weight in the portfolio. +
    }> + + +
    +
    + + Percentage Contribution to Risk (Risk %) shows how much of the portfolio’s total risk comes from a specific asset, taking into account both how risky the asset is (MCR) and how much of the portfolio it represents (weight). For example, if a stock has a Risk % of 35%, that means 35% of the portfolio’s total risk comes from that single stock. +
    }> + + +
    +
    + + {this.state.twoYearRisk?.rows ? + this.state.twoYearRisk.rows.map((asset, index) => ( +
    +
    {asset.ticker}
    +
    {this.percentFormatter.format(asset.weight)}
    +
    {this.percentFormatter.format(asset.mcr)}
    +
    {this.percentFormatter.format(asset.pctRc)}
    +
    + )) : + null + } +
    +
    + {this.state.twoYearRisk?.corr ? this.renderCorrHeatmap(this.state.twoYearRisk.corr) : null} +
    + + +
    + : + <> + { } + + } +
    + ); + } + + renderCorrHeatmap(corrDf, title = "Correlation Heatmap (2-Year Time Horizon)") { + if (!corrDf) return null; + + const { tickers, cells } = this.corrDfToHeatmapCells(corrDf); + + // Map correlation [-1,1] to 0..100 for CSS lightness + const colorFor = (v) => { + // clamp + const x = Math.max(-1, Math.min(1, v)); + // 0 => neutral, -1 => one extreme, +1 => other extreme + // Use HSL: red-ish for negative, green-ish for positive + const hue = x >= 0 ? 120 : 0; // green or red + const sat = 55; + const light = 92 - Math.abs(x) * 45; // stronger corr => darker + return `hsl(${hue} ${sat}% ${light}%)`; + }; + + return ( +
    +

    {title}

    +
    +
    +
    + {tickers.map(t => ( +
    + {t} +
    + ))} + + {tickers.map(r => ( + +
    {r}
    + {tickers.map(c => { + const cell = cells.find(x => x.row === r && x.col === c); + const v = cell?.value ?? 0; + return ( +
    + {v.toFixed(2)} +
    + ); + })} +
    + ))} +
    +
    +
    + Values near +1 move together; values near -1 move opposite; values near 0 are weakly related. +
    +
    + ); + } + + renderStockCard(company, symbol, currentPrice, purchasePrice, quantity, gains, percentGain) { + return ( +
    +

    {company} ({symbol})

    +

    Current Price: ${currentPrice.toFixed(2)}

    +

    Purchase Price: ${purchasePrice.toFixed(2)}

    +

    Quantity: {quantity}

    +

    Gains: = 0 ? 'positive' : 'negative'}`}>${gains.toFixed(2)}

    +

    % Gain: = 0 ? 'positive' : 'negative'}`}>{percentGain.toFixed(2)}%

    +
    + ); + } +} + +export default RiskAnalysis; diff --git a/open-fin-al/src/View/Settings.jsx b/open-fin-al/src/View/Settings.jsx index ffd3c3a4..fef02bb4 100644 --- a/open-fin-al/src/View/Settings.jsx +++ b/open-fin-al/src/View/Settings.jsx @@ -1,8 +1,12 @@ -import React, { useRef, useEffect, useState, useLayoutEffect } from "react"; +import React, { useRef, useEffect, useState, useLayoutEffect, useMemo } from "react"; import { useNavigate, useLocation } from 'react-router-dom'; import { SettingsInteractor } from "../Interactor/SettingsInteractor"; import { JSONRequest } from "../Gateway/Request/JSONRequest"; +import { withViewComponent } from "../hoc/withViewComponent"; +import { ViewComponent } from "../types/ViewComponent"; import { SettingsRow } from "./Settings/Row"; + +const WrappedSettingsRow = withViewComponent(SettingsRow); import { InitializationInteractor } from "../Interactor/InitializationInteractor"; import { useHeader } from "./App/LoadedLayout"; @@ -143,6 +147,14 @@ function Settings(props) { getDarkMode(); }, []); + const settingsRowConfig = useMemo(() => new ViewComponent({ + height: 48, width: 600, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 1, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + label: "Settings Row", description: "A single row in the settings panel", + tags: ["settings", "row", "configuration"], minimumProficiencyRequirements: {}, requiresInternet: false, + }), []); + const navigate = useNavigate(); const location = useLocation(); @@ -172,7 +184,7 @@ function Settings(props) {
    {sections.response && sections.response.results.length > 0 && sections.response.results.map((section) => ( -
    +

    {section.label}

    @@ -180,9 +192,7 @@ function Settings(props) {
    Value
    {section.configurations.map((configuration) => ( - <> - - + ))}
    diff --git a/open-fin-al/src/View/Stock.jsx b/open-fin-al/src/View/Stock.jsx index f1c8709e..017be43a 100644 --- a/open-fin-al/src/View/Stock.jsx +++ b/open-fin-al/src/View/Stock.jsx @@ -4,11 +4,12 @@ // Disclaimer of Liability // The authors of this software disclaim all liability for any damages, including incidental, consequential, special, or indirect damages, arising from the use or inability to use this software. -import React, { useContext, useEffect, useState } from "react"; +import React, { useContext, useEffect, useMemo, useState } from "react"; import { NavLink, useLocation } from "react-router-dom"; -import { TimeSeriesChart } from "./Stock/TimeSeriesChart"; -import { TickerSearchBar } from "./Stock/TickerSearchBar"; -import { TickerSidePanel } from "./Stock/TickerSidePanel"; + +import { WrappedTickerSearchBar, WrappedTimeSeriesChart, WrappedTickerSidePanel } from "../hoc/WrappedComponents"; +import { ViewComponent } from "../types/ViewComponent"; + import { DataContext } from "./App"; import { SecInteractor } from "../Interactor/SecInteractor"; @@ -26,6 +27,9 @@ function Stock(props) { const { setHeader } = useHeader(); + + + useEffect(() => { setHeader({ title: "Trade", @@ -134,7 +138,7 @@ function Stock(props) { const reportResults10K = await secInteractor.get(req10K); const reportResults10Q = await secInteractor.get(req10Q); - + window.console.log(reportResults10K, reportResults10Q); if(reportResults10K && reportResults10Q) { // Update the DataContext state to include reportLinks if they exist setState((prevState) => ({ @@ -152,44 +156,116 @@ function Stock(props) { } }, [state?.cik, state?.ticker, state?.data, setState]); // Added setState to dependency - return ( + // ── ViewComponent configs — useMemo prevents recreation on every render ── + const tickerSearchConfig = useMemo(() => new ViewComponent({ + height: 50, + width: 400, + isContainer: false, + resizable: false, + maintainAspectRatio: false, + heightRatio: 1, + widthRatio: 8, + heightWidthRatioMultiplier: 0.125, + visible: true, + enabled: true, + label: "Ticker Search Bar", + description: "Search bar for looking up stock ticker symbols", + tags: ["search", "ticker", "stock", "input"], + minimumProficiencyRequirements: { "basic": 1 }, + requiresInternet: true, + }), []); + + const timeSeriesConfig = useMemo(() => new ViewComponent({ + height: 400, + width: 800, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + heightRatio: 1, + widthRatio: 2, + heightWidthRatioMultiplier: 0.5, + visible: true, + enabled: true, + label: "Time Series Chart", + description: "Chart displaying stock price and volume over time", + tags: ["chart", "price", "volume", "stock"], + minimumProficiencyRequirements: { "basic": 1 }, + requiresInternet: true, + }), []); + + const sidePanelConfig = useMemo(() => new ViewComponent({ + height: 600, + width: 300, + isContainer: true, + resizable: false, + maintainAspectRatio: false, + heightRatio: 1, + widthRatio: 1, + heightWidthRatioMultiplier: 1, + visible: true, + enabled: true, + label: "Ticker Side Panel", + description: "Side panel displaying SEC fundamental data and AI analysis", + tags: ["panel", "fundamentals", "sec", "analysis"], + minimumProficiencyRequirements: { "intermediate": 2 }, + requiresInternet: true, + }), []); + +return (
    - {state ? - ( - <> - - - { state.isLoading === true ? ( - <> -

    Loading...

    - + {state ? ( + <> +
    + + {state.isLoading === true ? ( +
    +

    Retreiving data...

    +
    +
    ) : state.error ? ( -

    The ticker you entered is not valid or no data is available for this stock.

    - ) : ( -

    Data Source: {state.dataSource}

    - )} - - - - ) : - (

    Loading Context...

    ) - } +

    + The ticker you entered is not valid or no data is available for this stock. +

    + ) : state.dataSource ? ( +

    + Data Source: {state.dataSource} +

    + ) : null} +
    + + + + ) : ( +

    Loading Context...

    + )}
    - { state && state.secData ? ( - <> - - - ) : (null)} + {state && state.secData ? ( + + ) : null}
    ); } -// In case hooks are needed for this class. Can remove later if not necessary export function TimeSeries() { - return -}; \ No newline at end of file + return ; +} \ No newline at end of file diff --git a/open-fin-al/src/View/Stock/TickerSearchBar.jsx b/open-fin-al/src/View/Stock/TickerSearchBar.jsx index caafa91d..588eb0af 100644 --- a/open-fin-al/src/View/Stock/TickerSearchBar.jsx +++ b/open-fin-al/src/View/Stock/TickerSearchBar.jsx @@ -11,89 +11,112 @@ import { JSONRequest } from "../../Gateway/Request/JSONRequest"; import { SymbolSearchBar } from "../Shared/SymbolSearchBar"; function TickerSearchBar(props) { - //TODO: implement error handling + const handleError = (state, error) => { + window.console.error("TickerSearchBar error:", error); + + const updatedState = { + ...state, + error: true, + initializing: true, + isLoading: false, + ticker: state?.searchRef || state?.ticker || null + }; + + props.handleDataChange(updatedState); + return updatedState; + }; //Gets all data for a ticker and updates the props with the data const fetchAllData = async (newState, fetchSec=true) => { + if(!newState) return; + newState.isLoading = true; props.handleDataChange(newState); - if(newState.securitiesList) { - for(var security of newState.securitiesList) { - if(security.symbol === newState.searchRef) { - newState.assetId = security.id; - break; + try { + if(newState.securitiesList) { + for(var security of newState.securitiesList) { + if(security.symbol === newState.searchRef) { + newState.assetId = security.id; + break; + } } } - } - //Get Price Data - newState = await fetchPriceVolumeData(newState); + //Get Price Data + newState = await fetchPriceVolumeData(newState); - //Get SEC Data - if(fetchSec && newState.error === false) { - newState = await fetchRatioData(newState); + //Get SEC Data + if(fetchSec && newState.error === false) { + newState = await fetchRatioData(newState); + } + + props.handleDataChange(newState); + } catch(error) { + handleError(newState, error); } - - props.handleDataChange(newState); } //Gets price and volume data for a ticker const fetchPriceVolumeData = async (newState) => { - // TODO: can we store cik in the securities list as well? - // get company name from securities list data - var companyName = ""; - var cik = ""; - newState.securitiesList.find((element) => { - if(element.ticker === newState.searchRef) { - companyName = element.companyName; - cik = element.cik; - } - }); - - //get price and volume data through stock interactor - var interactor = new StockInteractor(); - var requestObj = new JSONRequest(`{ - "request": { - "stock": { - "action": "${newState.type}", - "ticker": "${newState.searchRef}", - "cik": "${cik}", - "companyName": "${companyName}", - "interval": "${newState.interval}" + try { + // TODO: can we store cik in the securities list as well? + // get company name from securities list data + var companyName = ""; + var cik = ""; + newState.securitiesList.find((element) => { + if(element.ticker === newState.searchRef) { + companyName = element.companyName; + cik = element.cik; + } + }); + + //get price and volume data through stock interactor + var interactor = new StockInteractor(); + var requestObj = new JSONRequest(`{ + "request": { + "stock": { + "action": "${newState.type}", + "ticker": "${newState.searchRef}", + "cik": "${cik}", + "companyName": "${companyName}", + "interval": "${newState.interval}" + } } + }`); + + const results = await interactor.get(requestObj); + + //if the results come back with a status of 400, set error. + if(!results || (results.status && results.status >= 400)) { + newState.error = true; + newState.initializing = true; + newState.ticker = newState.searchRef; + newState.cik = cik; + newState.isLoading = false; + return newState; } - }`); - const results = await interactor.get(requestObj); + var priceData = results; - //if the results come back with a status of 400, set error. - if(results.status && results.status === 400) { - newState.error = true; + //Update the state + newState.error = false; newState.initializing = true; + newState.data = priceData; + newState.dataSource = results.source; newState.ticker = newState.searchRef; newState.cik = cik; newState.isLoading = false; + newState.priceMin = Math.min(...priceData.response.results[0]["data"].map(data => data.price)); + newState.priceMax = Math.max(...priceData.response.results[0]["data"].map(data => data.price)); + newState.maxVolume = Math.max(...priceData.response.results[0]["data"].map(data => data.volume)); + newState.yAxisStart = dateTimeFormatter(priceData.response.results[0]["data"][0]); + newState.yAxisEnd = dateTimeFormatter(priceData.response.results[0]["data"][-1]); + return newState; + } catch(error) { + return handleError(newState, error); } - - var priceData = results; - - //Update the state - newState.error = false; - newState.initializing = true; - newState.data = priceData; - newState.dataSource = results.source; - newState.ticker = newState.searchRef; - newState.cik = cik; - newState.isLoading = false; - newState.priceMin = Math.min(...priceData.response.results[0]["data"].map(data => data.price)); - newState.priceMax = Math.max(...priceData.response.results[0]["data"].map(data => data.price)); - newState.maxVolume = Math.max(...priceData.response.results[0]["data"].map(data => data.volume)); - newState.yAxisStart = dateTimeFormatter(priceData.response.results[0]["data"][0]); - newState.yAxisEnd = dateTimeFormatter(priceData.response.results[0]["data"][-1]); - - return newState; } //Gets SEC data for a ticker @@ -214,4 +237,4 @@ function TickerSearchBar(props) { ); } -export { TickerSearchBar } \ No newline at end of file +export { TickerSearchBar } diff --git a/open-fin-al/src/View/Stock/TimeSeriesChart.jsx b/open-fin-al/src/View/Stock/TimeSeriesChart.jsx index 8e41d68f..fe179832 100644 --- a/open-fin-al/src/View/Stock/TimeSeriesChart.jsx +++ b/open-fin-al/src/View/Stock/TimeSeriesChart.jsx @@ -11,6 +11,7 @@ import { StockInteractor } from "../../Interactor/StockInteractor"; import { JSONRequest } from "../../Gateway/Request/JSONRequest"; import { UserInteractor } from "../../Interactor/UserInteractor"; import { PortfolioInteractor } from "../../Interactor/PortfolioInteractor"; +import {PortfolioTransactionInteractor} from "../../Interactor/PortfolioTransactionInteractor"; import { OrderInteractor } from "../../Interactor/OrderInteractor"; function TimeSeriesChart(props) { @@ -26,6 +27,8 @@ function TimeSeriesChart(props) { const [orderQuantity, setOrderQuantity] = useState(0); const [timeoutId, setTimeoutId] = useState(null); const [cashId, setCashId] = useState(null); + const [buyingPower, setBuyingPower] = useState(0); + const [buyingPowerLoaded, setBuyingPowerLoaded] = useState(false); const openModal = async () => { setIsModalOpen(true); @@ -114,6 +117,48 @@ function TimeSeriesChart(props) { return null; }; + const getBuyingPower = async(cashIdP=null, portfolioId=null) => { + try { + if(!cashIdP) { + cashIdP = cashId; + } + + if(!portfolioId) { + portfolioId = currentPortfolio; + } + + const interactor = new PortfolioTransactionInteractor(); + const requestObj = new JSONRequest(JSON.stringify({ + request: { + action: "getBuyingPower", + transaction: { + portfolioId: portfolioId, + entry: { + assetId: cashIdP + } + } + } + })); + + const response = await interactor.get(requestObj); + if(response && response.response && response.response.ok && response.response.results && response.response.results[0]) { + setBuyingPowerLoaded(true); + setBuyingPower(response.response.results[0].buyingPower); + return true; + } else { + console.error('Buying power API response error:', response); + setBuyingPowerLoaded(true); + setBuyingPower(0); + return false; + } + } catch (error) { + console.error('Error fetching buying power:', error); + setBuyingPowerLoaded(true); + setBuyingPower(0); + return false; + } + }; + const getCurrentPrice = async () => { if(props.state.data) { const interactor = new StockInteractor(); @@ -141,6 +186,8 @@ function TimeSeriesChart(props) { const placeOrder = async () => { //TODO: check to make sure the order and pending orders don't exceed buying power + getBuyingPower(); + const interactor = new OrderInteractor(); const requestObj = new JSONRequest(JSON.stringify({ request: { @@ -314,10 +361,16 @@ function TimeSeriesChart(props) { - {props.state.secData ? - <> -
    -

    + {data && +
    +

    + +

    {isModalOpen && ( <>
    { @@ -327,7 +380,7 @@ function TimeSeriesChart(props) {
    -

    {header}

    +

    Purchase {header}

    + { buyingPowerLoaded && currentQuote.quotePrice ? + <> +

    Price: {formatterCent.format(currentQuote.quotePrice)}

    +

    Quantity: setOrderQuantity(e.target.value)} />

    +

    Buying Power: {formatterCent.format(buyingPower)}

    +

    Total: {formatterCent.format(currentQuote.quotePrice * orderQuantity)}

    + {orderMessage ?

    {orderMessage}

    : null} + + {(currentQuote.quotePrice * orderQuantity) <= buyingPower ? + + : +

    The order total may not exceed your buying power

    } + + : +
    + Retrieving current quote...
    +
    + } +
    )}
    + } + + {props.state.secData ? + <> { props.fundamentalAnalysis ? <>

    AI Fundamental Analysis

    diff --git a/open-fin-al/src/declarations.d.ts b/open-fin-al/src/declarations.d.ts new file mode 100644 index 00000000..be48951e --- /dev/null +++ b/open-fin-al/src/declarations.d.ts @@ -0,0 +1,23 @@ +declare module "*.jsx" { + import React from "react"; + const component: React.ComponentType; + export default component; + export { component }; +} + +/* + +This one file covers **every `.jsx` import across your entire project** — no matter how many components you add in the future. + + +**The full picture of how type safety still works** + +Even with the global declaration silencing the import error, your type safety is **not lost** because: + +WrappedComponents.ts ← still .ts, still typed + ↓ +withViewComponent.tsx ← still enforces ViewComponent interface + ↓ +Stock.jsx ← viewConfig is still typed at point of use + +*/ \ No newline at end of file diff --git a/open-fin-al/src/global.d.ts b/open-fin-al/src/global.d.ts new file mode 100644 index 00000000..c48c26b4 --- /dev/null +++ b/open-fin-al/src/global.d.ts @@ -0,0 +1 @@ +declare module "*.jsx"; \ No newline at end of file diff --git a/open-fin-al/src/hoc/WrappedComponents.ts b/open-fin-al/src/hoc/WrappedComponents.ts new file mode 100644 index 00000000..bd69efe7 --- /dev/null +++ b/open-fin-al/src/hoc/WrappedComponents.ts @@ -0,0 +1,109 @@ +import { withViewComponent } from "./withViewComponent"; + +// Stock +import { TimeSeriesChart } from "../View/Stock/TimeSeriesChart"; +import { TickerSearchBar } from "../View/Stock/TickerSearchBar"; +import { TickerSidePanel } from "../View/Stock/TickerSidePanel"; + +// Dashboard +import { EconomicChart } from "../View/Dashboard/EconomicChart"; + +// Learning Module +import { Slide } from "../View/LearningModule/Slideshow/Slide"; +import { SlideshowWindow } from "../View/LearningModule/Slideshow/SlideshowWindow"; +import { LearningModuleDetails } from "../View/LearningModule/LearningModuleDetails"; +import { LearningModulePage } from "../View/LearningModule/LearningModulePage"; + +// News +import { NewsListingSummary } from "../View/News/Listing/Summary"; +import { NewsSearchBar } from "../View/News/SearchBar"; +import { NewsBrowser } from "../View/News/Browser"; +import { NewsListing } from "../View/News/Listing"; + +// Portfolio +import { PortfolioCreation } from "../View/Portfolio/Creation"; + +// Settings +import { SettingsRow } from "../View/Settings/Row"; +import { SettingsRowLabel } from "../View/Settings/RowLabel"; +import { SettingsRowValue } from "../View/Settings/RowValue"; + +// Shared +import { SymbolSearchBar } from "../View/Shared/SymbolSearchBar"; + +// Top-level views +import About from "../View/About"; +import { Analysis } from "../View/Analysis"; +import BuyReport from "../View/BuyReport"; +import Chatbot from "../View/Chatbot"; +import Forecast from "../View/Forecast"; +import { ForecastFeature } from "../View/ForecastFeature"; +import ForecastModel from "../View/ForecastModel"; +import Home from "../View/Home"; +import InvestmentPool from "../View/InvestmentPool"; +import { Learn } from "../View/Learn"; +import { MovingAvgChart } from "../View/MovingAVGChart"; +import { News } from "../View/News"; +import Portfolio from "../View/Portfolio"; +import RiskAnalysis from "../View/RiskAnalysis"; +import RiskSurvey from "../View/RiskSurvey"; +import { ROCChart } from "../View/ROCChart"; +import { RSIChart } from "../View/RSIChart"; +import { Settings } from "../View/Settings"; +import { TimeSeries } from "../View/Stock"; +import StockAnalysis from "../View/StockAnalysis"; +import { StockAnalysisSearchBar } from "../View/StockAnalysisSearchBar"; + +// Stock +export const WrappedTickerSearchBar = withViewComponent(TickerSearchBar); +export const WrappedTimeSeriesChart = withViewComponent(TimeSeriesChart); +export const WrappedTickerSidePanel = withViewComponent(TickerSidePanel); + +// Dashboard +export const WrappedEconomicChart = withViewComponent(EconomicChart); + +// Learning Module +export const WrappedSlide = withViewComponent(Slide); +export const WrappedSlideshowWindow = withViewComponent(SlideshowWindow); +export const WrappedLearningModuleDetails = withViewComponent(LearningModuleDetails); +export const WrappedLearningModulePage = withViewComponent(LearningModulePage); + +// News +export const WrappedNewsListingSummary = withViewComponent(NewsListingSummary); +export const WrappedNewsSearchBar = withViewComponent(NewsSearchBar); +export const WrappedNewsBrowser = withViewComponent(NewsBrowser); +export const WrappedNewsListing = withViewComponent(NewsListing); + +// Portfolio +export const WrappedPortfolioCreation = withViewComponent(PortfolioCreation); + +// Top-level views +export const WrappedAbout = withViewComponent(About); +export const WrappedAnalysis = withViewComponent(Analysis); +export const WrappedBuyReport = withViewComponent(BuyReport); +export const WrappedChatbot = withViewComponent(Chatbot); +export const WrappedForecast = withViewComponent(Forecast); +export const WrappedForecastFeature = withViewComponent(ForecastFeature); +export const WrappedForecastModel = withViewComponent(ForecastModel); +export const WrappedHome = withViewComponent(Home); +export const WrappedInvestmentPool = withViewComponent(InvestmentPool); +export const WrappedLearn = withViewComponent(Learn); +export const WrappedMovingAvgChart = withViewComponent(MovingAvgChart); +export const WrappedNews = withViewComponent(News); +export const WrappedPortfolio = withViewComponent(Portfolio); +export const WrappedRiskAnalysis = withViewComponent(RiskAnalysis); +export const WrappedRiskSurvey = withViewComponent(RiskSurvey); +export const WrappedROCChart = withViewComponent(ROCChart); +export const WrappedRSIChart = withViewComponent(RSIChart); +export const WrappedSettings = withViewComponent(Settings); +export const WrappedTimeSeries = withViewComponent(TimeSeries); +export const WrappedStockAnalysis = withViewComponent(StockAnalysis); +export const WrappedStockAnalysisSearchBar = withViewComponent(StockAnalysisSearchBar); + +// Settings +export const WrappedSettingsRow = withViewComponent(SettingsRow); +export const WrappedSettingsRowLabel = withViewComponent(SettingsRowLabel); +export const WrappedSettingsRowValue = withViewComponent(SettingsRowValue); + +// Shared +export const WrappedSymbolSearchBar = withViewComponent(SymbolSearchBar); diff --git a/open-fin-al/src/hoc/registerComponents.ts b/open-fin-al/src/hoc/registerComponents.ts new file mode 100644 index 00000000..16ce017e --- /dev/null +++ b/open-fin-al/src/hoc/registerComponents.ts @@ -0,0 +1,642 @@ +import { ComponentRegistry } from "../types/ComponentRegistry"; +import { ViewComponent } from "../types/ViewComponent"; + +const registry = ComponentRegistry.getInstance(); + +const componentConfigs: Array<{ id: string; config: any }> = [ + // Stock + { + id: "time-series-chart", + config: { + label: "Time Series Chart", + description: "Displays stock price history as a time series chart", + tags: ["chart", "stock", "time series", "price", "graph"], + height: 300, + width: 700, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + { + id: "ticker-search-bar", + config: { + label: "Ticker Search Bar", + description: "Search bar for finding and selecting stock tickers", + tags: ["search", "ticker", "stock", "search bar"], + height: 50, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + { + id: "ticker-side-panel", + config: { + label: "Ticker Side Panel", + description: "Side panel displaying financial metrics for the selected ticker", + tags: ["panel", "ticker", "stock", "side panel", "metrics", "financial"], + height: 600, + width: 300, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 2, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + + // Dashboard + { + id: "economic-chart", + config: { + label: "Economic Chart", + description: "Displays macroeconomic data as a chart", + tags: ["chart", "economic", "macro", "graph", "economy"], + height: 300, + width: 700, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + + // Learning Module + { + id: "slide", + config: { + label: "Slide", + description: "Individual slide in a slideshow presentation", + tags: ["slide", "presentation", "slideshow", "learning"], + height: 450, + width: 800, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "slideshow-window", + config: { + label: "Slideshow Window", + description: "Window for displaying slideshow presentations", + tags: ["slideshow", "presentation", "window", "learning"], + height: 450, + width: 800, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "learning-module-details", + config: { + label: "Learning Module Details", + description: "Displays details and information about a learning module", + tags: ["learning", "module", "details", "education"], + height: 400, + width: 600, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 3, + heightRatio: 2, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "learning-module-page", + config: { + label: "Learning Module Page", + description: "Full page view for a learning module", + tags: ["learning", "module", "page", "education"], + height: 600, + width: 800, + isContainer: true, + resizable: true, + maintainAspectRatio: false, + widthRatio: 4, + heightRatio: 3, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "powerpoint", + config: { + label: "PowerPoint Learning Module", + description: "Component for displaying PowerPoint presentations", + tags: ["PowerPoint", "Presentation", "Slideshow", "Learning Module"], + height: null, + width: null, + isContainer: false, + resizable: true, + maintainAspectRatio: true, + widthRatio: 16, + heightRatio: 9, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + + // News + { + id: "news-listing-summary", + config: { + label: "News Listing Summary", + description: "Summary view of a news article in a listing", + tags: ["news", "summary", "listing", "article"], + height: 120, + width: 600, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 5, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + { + id: "news-search-bar", + config: { + label: "News Search Bar", + description: "Search bar for finding news articles", + tags: ["news", "search", "search bar"], + height: 50, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + { + id: "news-browser", + config: { + label: "News Browser", + description: "Browser for viewing and navigating news articles", + tags: ["news", "browser", "articles"], + height: 600, + width: 800, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 4, + heightRatio: 3, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + { + id: "news-listing", + config: { + label: "News Listing", + description: "List view of news articles", + tags: ["news", "listing", "articles", "list"], + height: 600, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 2, + heightRatio: 3, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + + // Settings + { + id: "settings-row", + config: { + label: "Settings Row", + description: "A single row in the settings panel", + tags: ["settings", "row", "configuration"], + height: 48, + width: 600, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "settings-row-label", + config: { + label: "Settings Row Label", + description: "Label element for a settings row", + tags: ["settings", "label", "configuration"], + height: 48, + width: 200, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + { + id: "settings-row-value", + config: { + label: "Settings Row Value", + description: "Value element for a settings row", + tags: ["settings", "value", "configuration"], + height: 48, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: false, + }, + }, + + // Shared + { + id: "symbol-search-bar", + config: { + label: "Symbol Search Bar", + description: "Shared search bar for finding financial symbols", + tags: ["search", "symbol", "ticker", "shared", "search bar"], + height: 50, + width: 400, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 1, + heightRatio: 1, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, + + // Top-level views + { + id: "about", + config: { + label: "About", + description: "About page for the application", + tags: ["about", "info", "information"], + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: false, + }, + }, + { + id: "analysis", + config: { + label: "Analysis", + description: "Stock and financial analysis view", + tags: ["analysis", "stock", "financial", "research"], + height: 600, width: 1000, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "buy-report", + config: { + label: "Buy Report", + description: "Report view for buy recommendations", + tags: ["buy", "report", "recommendation", "stock"], + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "chatbot", + config: { + label: "Chatbot", + description: "AI chatbot for financial questions and commands", + tags: ["chatbot", "ai", "assistant", "chat"], + height: 500, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 2, heightRatio: 5, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "forecast", + config: { + label: "Forecast", + description: "Stock price forecast view", + tags: ["forecast", "prediction", "stock", "price"], + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "forecast-feature", + config: { + label: "Forecast Feature", + description: "Individual feature input for the forecast model", + tags: ["forecast", "feature", "input", "model"], + height: 80, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: false, + }, + }, + { + id: "forecast-model", + config: { + label: "Forecast Model", + description: "Configuration and display of the forecast model", + tags: ["forecast", "model", "machine learning", "prediction"], + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "home", + config: { + label: "Home", + description: "Application home page and dashboard", + tags: ["home", "dashboard", "overview"], + height: 600, width: 1000, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "investment-pool", + config: { + label: "Investment Pool", + description: "View for managing investment pools", + tags: ["investment", "pool", "portfolio", "management"], + height: 600, width: 800, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "learn", + config: { + label: "Learn", + description: "Learning hub for financial education modules", + tags: ["learn", "education", "modules", "courses"], + height: 600, width: 1000, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: false, + }, + }, + { + id: "moving-avg-chart", + config: { + label: "Moving Average Chart", + description: "Chart displaying moving average indicators for a stock", + tags: ["chart", "moving average", "indicator", "stock", "technical analysis"], + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "news", + config: { + label: "News", + description: "Financial news page", + tags: ["news", "articles", "financial news"], + height: 600, width: 800, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "portfolio", + config: { + label: "Portfolio", + description: "Portfolio management and overview page", + tags: ["portfolio", "investments", "holdings", "management"], + height: 600, width: 1000, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "risk-analysis", + config: { + label: "Risk Analysis", + description: "Risk analysis view for evaluating investment risk", + tags: ["risk", "analysis", "investment", "assessment"], + height: 600, width: 1000, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "risk-survey", + config: { + label: "Risk Survey", + description: "Survey for assessing user risk tolerance", + tags: ["risk", "survey", "questionnaire", "tolerance"], + height: 600, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: false, + }, + }, + { + id: "roc-chart", + config: { + label: "ROC Chart", + description: "Rate of Change chart for technical stock analysis", + tags: ["chart", "ROC", "rate of change", "indicator", "technical analysis"], + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "rsi-chart", + config: { + label: "RSI Chart", + description: "Relative Strength Index chart for technical stock analysis", + tags: ["chart", "RSI", "relative strength index", "indicator", "technical analysis"], + height: 300, width: 700, isContainer: false, resizable: true, + maintainAspectRatio: true, widthRatio: 16, heightRatio: 9, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "settings", + config: { + label: "Settings", + description: "Application settings and configuration page", + tags: ["settings", "configuration", "preferences", "options"], + height: 600, width: 700, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 4, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: false, + }, + }, + { + id: "time-series", + config: { + label: "Time Series", + description: "Full stock time series view with charts and data", + tags: ["stock", "time series", "chart", "price history"], + height: 600, width: 1000, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "stock-analysis", + config: { + label: "Stock Analysis", + description: "Detailed stock analysis page with multiple indicators", + tags: ["stock", "analysis", "indicators", "technical analysis"], + height: 600, width: 1000, isContainer: true, resizable: true, + maintainAspectRatio: false, widthRatio: 5, heightRatio: 3, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + { + id: "stock-analysis-search-bar", + config: { + label: "Stock Analysis Search Bar", + description: "Search bar for the stock analysis page", + tags: ["search", "stock", "analysis", "search bar"], + height: 50, width: 400, isContainer: false, resizable: true, + maintainAspectRatio: false, widthRatio: 1, heightRatio: 1, + heightWidthRatioMultiplier: 0, visible: true, enabled: true, + minimumProficiencyRequirements: {}, requiresInternet: true, + }, + }, + + // Portfolio + { + id: "portfolio-creation", + config: { + label: "Portfolio Creation", + description: "Interface for creating and managing investment portfolios", + tags: ["portfolio", "creation", "investment", "management"], + height: 600, + width: 800, + isContainer: false, + resizable: true, + maintainAspectRatio: false, + widthRatio: 4, + heightRatio: 3, + heightWidthRatioMultiplier: 0, + visible: true, + enabled: true, + minimumProficiencyRequirements: {}, + requiresInternet: true, + }, + }, +]; + +export function registerAllComponents(): void { + for (const { id, config } of componentConfigs) { + if (!registry.getById(id)) { + registry.register(id, new ViewComponent(config)); + } + } +} diff --git a/open-fin-al/src/hoc/withViewComponent.tsx b/open-fin-al/src/hoc/withViewComponent.tsx new file mode 100644 index 00000000..b5151a63 --- /dev/null +++ b/open-fin-al/src/hoc/withViewComponent.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import { ViewComponent } from "../types/ViewComponent"; + +// The props the HOC injects — every wrapped component gets these +export interface WithViewComponentProps { + viewConfig: ViewComponent; +} + +// The HOC — wraps any .jsx component and enforces ViewComponent type safety +export function withViewComponent

    ( + WrappedComponent: React.ComponentType

    +) { + const displayName = WrappedComponent.displayName || WrappedComponent.name || "Component"; + + function ViewComponentWrapper(props: P & WithViewComponentProps) { + const { viewConfig, ...rest } = props; + + // Guard against missing viewConfig (e.g. component rendered without prop) + if (!viewConfig) return null; + + // Centralized visibility guard — no need to handle this in each .jsx file + if (!viewConfig.getVisible()) return null; + + return ( +

    + +
    + ); + } + + ViewComponentWrapper.displayName = `WithViewComponent(${displayName})`; + + return ViewComponentWrapper; +} diff --git a/open-fin-al/src/index.css b/open-fin-al/src/index.css index 97c22402..f6d696f6 100644 --- a/open-fin-al/src/index.css +++ b/open-fin-al/src/index.css @@ -18,9 +18,11 @@ --text-color-medium-dark: #333333; --row-primary-color: #FFFFFF; --row-alternating-color: #c1c9ff; + --always-black: #000000; --footer-height: 90px; --sidebar-width: 220px; --sidebar-footer-width: 190px; + --pptx-scale: 1; } body.dark-mode { @@ -41,6 +43,7 @@ body.dark-mode { --text-color-medium-dark: #BBBBBB; --row-primary-color: #2d3748; --row-alternating-color: #4a5568; + --always-black: #000000; } body { @@ -384,10 +387,17 @@ code { background-color: var(--background-color); } -.pptx-preview-wrapper { +.slideshowContainer { margin: 0 !important; padding: 0 !important; - overflow: hidden !important; + position: relative; + overflow: hidden; +} + +.pptx-preview-wrapper { + transform-origin: top left; + transform: scale(var(--pptx-scale, 1)); + overflow: hidden; } .slide { @@ -490,7 +500,10 @@ code { background-color: var(--secondary-color); color: var(--text-color-light); border-radius: 10px 10px 0px 0px; - height: 200px + height: 200px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; } .cardContainer { @@ -511,6 +524,7 @@ code { .chartContainer { width: 700px; margin-left: 10px; + margin-top: 20px; } .stockDetails { @@ -552,13 +566,20 @@ code { padding: 0; } +.priceSearchFormContainer form { + display: flex; + align-items: center; + gap: 8px; +} + .priceSearchBar { padding: 8px; - width: 400px; + flex: 1; + min-width: 200px; border: 1px solid black; height: 30px; border-radius: 4px; - margin-right: 8px; + margin-right: 0; } .priceSearchButton { @@ -658,7 +679,7 @@ code { .popoverContent { max-width: 200px; - padding: 5px; + padding: 15px; border-radius: 10px; background-color: rgba(29, 32, 40, 0.9); color: var(--text-color-light) @@ -820,6 +841,10 @@ code { } .portfolio-card { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; background-color: var(--background-color); padding: 20px; border-radius: 5px; @@ -827,8 +852,12 @@ code { text-align: center; } +.portfolio-card h3 { + margin: 0px; +} + .portfolio-value, .buying-power { - font-size: 24px; + font-size: 20px; font-weight: bold; } @@ -1305,6 +1334,11 @@ nav ul li a:hover { color: var(--text-color-medium-dark); } +.loader-container { + display: flex; + align-items: center; +} + .small-loader { visibility: visible; border: 12px solid #f3f3f3; @@ -1322,6 +1356,25 @@ nav ul li a:hover { display: none; } +.tiny-loader { + visibility: visible; + border: 7px solid #f3f3f3; + border-top: 7px solid #3498db; + border-radius: 50%; + width: 7px; + height: 7px; + margin-left: 10px; + margin-right: 10px; + margin-top: 0px; + margin-bottom: 0px; + animation: spin 2s linear infinite; + display: inline-block; +} + +.tiny-loader.hidden { + display: none; +} + .error { color: red; } diff --git a/open-fin-al/src/index.html b/open-fin-al/src/index.html index 698597a2..743a5370 100644 --- a/open-fin-al/src/index.html +++ b/open-fin-al/src/index.html @@ -4,6 +4,7 @@ OpenFinAL: Open-source Financial Adaptive Learning System +