From 912f42e81cbd946285b7d5c5fa982e75c805a0a8 Mon Sep 17 00:00:00 2001 From: Oprea Alexandru Date: Sun, 10 Sep 2023 02:36:48 +0300 Subject: [PATCH 01/16] fixed confliciting name (#672) --- src/utils/inc/brainflow_array.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/inc/brainflow_array.h b/src/utils/inc/brainflow_array.h index 559145cba..5dba6e732 100644 --- a/src/utils/inc/brainflow_array.h +++ b/src/utils/inc/brainflow_array.h @@ -448,9 +448,9 @@ class BrainFlowArray } /// fill already preallocated buffer - void fill (T *ptr, int size) + void fill (T *ptr, int num) { - memcpy (origin, ptr, sizeof (T) * size); + memcpy (origin, ptr, sizeof (T) * num); } }; From f5bb7467a4955b1c12423f56f190324aa1d08ec0 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Tue, 12 Sep 2023 00:52:03 +0200 Subject: [PATCH 02/16] adding brainflow project for matlab, prepared toolbox (#674) Signed-off-by: Andrey Parfenov --- matlab_package/brainflow/BrainFlow.prj | 251 ++++++++++++++++++ matlab_package/brainflow/demos.xml | 89 +++++++ .../brainflow/doc/GettingStarted.mlx | Bin 0 -> 3496 bytes 3 files changed, 340 insertions(+) create mode 100644 matlab_package/brainflow/BrainFlow.prj create mode 100644 matlab_package/brainflow/demos.xml create mode 100644 matlab_package/brainflow/doc/GettingStarted.mlx diff --git a/matlab_package/brainflow/BrainFlow.prj b/matlab_package/brainflow/BrainFlow.prj new file mode 100644 index 000000000..be29b8d5b --- /dev/null +++ b/matlab_package/brainflow/BrainFlow.prj @@ -0,0 +1,251 @@ + + + BrainFlow + Andrey Parfenov + andrey@brainflow.org + BrainFlow + BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors. + BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors. + D:\workspace\brainflow\docs\_static\brainflow_logo.png + 5.9.0 + ${PROJECT_ROOT}\BrainFlow.mltbx + + + + + d956cedc-31c0-4ac2-8f12-dc5fe32043de + + true + <?xml version="1.0" encoding="utf-8"?> +<examples> + <exampleCategory name="examples"> + <example name="BandPowerAll" type="html"> + <file type="source">/examples/html/BandPowerAll.html</file> + <file type="main">/examples/BandPowerAll.m</file> + <file type="thumbnail"/> + </example> + <example name="BrainFlowGetData" type="html"> + <file type="source">/examples/html/BrainFlowGetData.html</file> + <file type="main">/examples/BrainFlowGetData.m</file> + <file type="thumbnail"/> + </example> + <example name="CSP" type="html"> + <file type="source">/examples/html/CSP.html</file> + <file type="main">/examples/CSP.m</file> + <file type="thumbnail"/> + </example> + <example name="Denoising" type="html"> + <file type="source">/examples/html/Denoising.html</file> + <file type="main">/examples/Denoising.m</file> + <file type="thumbnail"/> + </example> + <example name="Downsampling" type="html"> + <file type="source">/examples/html/Downsampling.html</file> + <file type="main">/examples/Downsampling.m</file> + <file type="thumbnail"/> + </example> + <example name="EEGMetrics" type="html"> + <file type="source">/examples/html/EEGMetrics.html</file> + <file type="main">/examples/EEGMetrics.m</file> + <file type="thumbnail"/> + </example> + <example name="ICA" type="html"> + <file type="source">/examples/html/ICA.html</file> + <file type="main">/examples/ICA.m</file> + <file type="thumbnail"/> + </example> + <example name="Markers" type="html"> + <file type="source">/examples/html/Markers.html</file> + <file type="main">/examples/Markers.m</file> + <file type="thumbnail"/> + </example> + <example name="PeaksDetection" type="html"> + <file type="source">/examples/html/PeaksDetection.html</file> + <file type="main">/examples/PeaksDetection.m</file> + <file type="thumbnail"/> + </example> + <example name="Serialization" type="html"> + <file type="source">/examples/html/Serialization.html</file> + <file type="main">/examples/Serialization.m</file> + <file type="thumbnail"/> + </example> + <example name="SignalFiltering" type="html"> + <file type="source">/examples/html/SignalFiltering.html</file> + <file type="main">/examples/SignalFiltering.m</file> + <file type="thumbnail"/> + </example> + <example name="Spo2" type="html"> + <file type="source">/examples/html/Spo2.html</file> + <file type="main">/examples/Spo2.m</file> + <file type="thumbnail">/examples/html/Spo2.png</file> + <file type="image">/examples/html/Spo2_01.png</file> + </example> + <example name="Transforms" type="html"> + <file type="source">/examples/html/Transforms.html</file> + <file type="main">/examples/Transforms.m</file> + <file type="thumbnail"/> + </example> + </exampleCategory> +</examples> + + + + + ${PROJECT_ROOT}\doc\GettingStarted.mlx + + /lib/pkgconfig + /lib/cmake/brainflow + /lib/cmake/GTest + /lib/cmake + + + true + + + + R2019b + latest + false + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${PROJECT_ROOT} + + + ${PROJECT_ROOT}\AggOperations.m + ${PROJECT_ROOT}\BoardIds.m + ${PROJECT_ROOT}\BoardShim.m + ${PROJECT_ROOT}\BrainFlowClassifiers.m + ${PROJECT_ROOT}\BrainFlowExitCodes.m + ${PROJECT_ROOT}\BrainFlowInputParams.m + ${PROJECT_ROOT}\BrainFlowMetrics.m + ${PROJECT_ROOT}\BrainFlowModelParams.m + ${PROJECT_ROOT}\BrainFlowPresets.m + ${PROJECT_ROOT}\DataFilter.m + ${PROJECT_ROOT}\demos.xml + ${PROJECT_ROOT}\DetrendOperations.m + ${PROJECT_ROOT}\doc + ${PROJECT_ROOT}\examples + ${PROJECT_ROOT}\FilterTypes.m + ${PROJECT_ROOT}\inc + ${PROJECT_ROOT}\IpProtocolTypes.m + ${PROJECT_ROOT}\lib + ${PROJECT_ROOT}\LogLevels.m + ${PROJECT_ROOT}\MLModel.m + ${PROJECT_ROOT}\NoiseEstimationLevelTypes.m + ${PROJECT_ROOT}\NoiseTypes.m + ${PROJECT_ROOT}\ThresholdTypes.m + ${PROJECT_ROOT}\WaveletDenoisingTypes.m + ${PROJECT_ROOT}\WaveletExtensionTypes.m + ${PROJECT_ROOT}\WaveletTypes.m + ${PROJECT_ROOT}\WindowOperations.m + + + + + + D:\workspace\brainflow\matlab_package\brainflow\BrainFlow.mltbx + + + + D:\Matlab\R2019b + + + + + + + + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + false + false + true + false + false + false + false + false + 10.0 + false + true + win64 + true + + + \ No newline at end of file diff --git a/matlab_package/brainflow/demos.xml b/matlab_package/brainflow/demos.xml new file mode 100644 index 000000000..0006e1ab7 --- /dev/null +++ b/matlab_package/brainflow/demos.xml @@ -0,0 +1,89 @@ + + + BrainFlow + toolbox + HelpIcon.DEMOS + + BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors. + + + + + other + BandPowerAll + examples/html/BandPowerAll.html + + + + other + BrainFlowGetData + examples/html/BrainFlowGetData.html + + + + other + CSP + examples/html/CSP.html + + + + other + Denoising + examples/html/Denoising.html + + + + other + Downsampling + examples/html/Downsampling.html + + + + other + EEGMetrics + examples/html/EEGMetrics.html + + + + other + ICA + examples/html/ICA.html + + + + other + Markers + examples/html/Markers.html + + + + other + PeaksDetection + examples/html/PeaksDetection.html + + + + other + Serialization + examples/html/Serialization.html + + + + other + SignalFiltering + examples/html/SignalFiltering.html + + + + other + Spo2 + examples/html/Spo2.html + + + + other + Transforms + examples/html/Transforms.html + + + \ No newline at end of file diff --git a/matlab_package/brainflow/doc/GettingStarted.mlx b/matlab_package/brainflow/doc/GettingStarted.mlx new file mode 100644 index 0000000000000000000000000000000000000000..a39429d111c2345d34fd26c4ef568b96c0137c55 GIT binary patch literal 3496 zcmaJ^c{Egy9-lC_shDgN50jsLizJag`_1}H4W<~PgR64 zr?5b>FxQ7Gq;3v&O~~o#i$ZguEz%o(Dx3XR()%~7Ic#FPeJo$B`3nG*mSNK);r>=+ zM@v&d8q3hH$3ec$f*txe8v+znuy(2b#qr}LVcj3Z9a{(_oEKWIqt&B}Spex_(mrD=Mxl?{W1 zIf`?l^L<*6(!0dW*MU|(B;R9csaF-`T^cJ!v{bnyFZ9 zMQCbm5x*x4x$w(^5=s+}^3ACcE{2|9G#{;nd=H%aS&?cs+QIn7Z!@Q{%_f#bMtA32 zx19B@TP$v~U5<+2h9Z-3JNcWm@L%+$^X~%-Q1xY^0{}o&eeLjQSC7-ud*`wwTjN$4 z_K02mp_?OEsEHOuKWY4AnA&75UrqSezpx^!pO*7l3?T+n=%MVnfbWI24>z6&^E=rV za1`mWn}v$M$uk8O;TGq*RfPJ(PQYElv-k!~o>)s?t)S<3Kvl^BrSmQNyKS)gqfJ2d?V)`BP1Ga)J4E--kTVDm(3n zGB?${=Q5F#GG;shFkcp~-o<8{OC#GYy~g`e0vjbPD+^N*rc|4bQgz(3Di-PKinKqC z!d)j|sgB*VD#>C3H>z`V$C7aw$wDYVHAl2MS-Zka>0ss8+$!cOFX|~w@K#^wiQaxg zOm-EKV3rhjfU>AA21a!ee|$5+O{n=WP+ew2weA{d^qs6si!TY%?}|F|0$N1C@};n8s9C)zN1ve z1*to<03^;ORD`zRK}{D!@XJnVzJwT^>FuT7)3PbAyd=dkKzJhn(Y;w%W^zd>qn4Hj zq9v4;9y}uH$T^Un#%fSJ<2be=*E&2L2}F!9td<^qu03XdEAH53ng_XOT<^utAhBXd zU3RlTePxBCt&L@6aLRg%xB`-}l_>yrb1Rfo^^+sT)uS5(9*3_@`2`0D2*znWj4QXA zRAi9nUdew?=3eZxu1^Nhoia)&ah-B{(=b?&3ec&o+Y&XAnmv;R@|Q+i)V0r3Sbo$! z1y{Qd>1pxaYYBdJ9>QumL16b~3esP}=&pVkrg6j0^9$RLrGMGv$jX_WQ)}#@Scl$u z@t1jR%A{cRK!()H7F&+`mEb7DXTFlktXBFN{q!f5wb^S%=pIw-u0^8j7G;!p1ZN+h zo|<#>0gbgK|BfyjwwK~u6HT}iGwkkG(hL_Inc;lLRxfvT`^?fM%j~o;wn~bh@o@T^ zG3KyOhGz}W+Fr2b^i#W=9GUsiebql`@y4dr@K!@|{8}laS0=GD?Ay^Y zsZrY8#E}R2op)L*O^gi0W^^q)#J+M?pk&WD$7Uds{x-e&-v5?|q&)Loxrb*~69p>l zktRbA?820Oto#0r*LG9nxz=)@bxJ4p_c}vy(UYy>UQU8j+GR>Z6F1iZ^qONYt7%fy%8|) zmBEd*$REnfu|N&FR$&NooN7U6*p(Yx5e+6*_Pj|w< z77z>XWp0&W{gIMbX9#5Bs{w1&`@z+&Vego}h(VbxO^jN%Sl2K2E%ix)B8%j;jb#bs zVS5{kJm?#r@n7;wL^HnPFiNON&pR>SE1fQ8f~JAnpz2g3LHu2I8{ih_X}g zRn}t8^CV62sMql;O^Jvg3UHs?-ltF@AkP#+CB{kv0PyUQLwh1oNKfSH>o`0bj>oy9 z@tzp8$6n5aC)gT??L{~9LVy^s{T-lgU`d~iO_uvp2ELOUgLyAL+Vr$7PRir&RFO{} z*;z#Vv&#YN$40s}ETcM^qSa$^Q=XR&xKy@+*cD$Adbc&S!o4QpRS#jvG>D|~XiM8q%hYY#tln=eu6vmtMbZIBoDp$$SDJ03pU@hXqQsFhscay}Jog{ep z#KT#&&a-XZyoFVIV!d3kgL2a*@YI=?Y>WKA3Mws&b?l%DsX-N$_n@Fy@Bfw5me}G< zBg-0LCp1Hj^K%yBsQ?<6MY-}{GoV*UGtd++-rhL2{$vsB@U4j$w7zmOtoAxGr#N-d zO$eB1*gsUA+SEo_wq<^#eq2*vY4(<6NB{h{@{-At`>_Rns8`DE4gYW<*%Z8uhlJEI z68!Jur~3@v!#*<9jpzJz!;mDV`5-HxqN1n@?;}gx;Buwy8xXlE)xb*o>zxRjQ zX_fvNHrQSK$Kt8P69%f0Vs|fm-`Qy0NPbN()||!WwGNUH>LPb!z69FAu9jCZNm!|r zczL>F6&X!_MuEkN1D!U~sXYPl_D6z3%Mae1PCFLhU4ZWDwbgk>V2W><9A`Uo&G&yT&M)>MPoC(H7ANP z(wnSD*s2QB)d+m|#?ViQMeBH0h!l~j^ooR(xpjJO!r12duk}*npeNDs(A~ft033FN z8Xf+fP^I|K@tdZ77~pVu+?)J2z%}aSK$Sc=_`9mKKUhkA!rv69!vKeaejh-Z z{=WeGv43# Date: Wed, 13 Sep 2023 17:03:53 -0400 Subject: [PATCH 03/16] AAVAA board addition (#668) * add aavaa board --------- Co-authored-by: farnoodf --- cpp_package/src/board_shim.cpp | 12 + cpp_package/src/inc/board_shim.h | 9 +- .../brainflow/board_controller_library.cs | 28 +- .../brainflow/brainflow/board_descr.cs | 5 +- .../brainflow/brainflow/board_shim.cs | 28 +- docs/DataFormatDesc.rst | 4 +- .../src/main/java/brainflow/BoardDescr.java | 4 +- .../src/main/java/brainflow/BoardIds.java | 3 +- .../src/main/java/brainflow/BoardShim.java | 6 +- julia_package/brainflow/src/board_shim.jl | 8 +- matlab_package/brainflow/BoardIds.m | 1 + matlab_package/brainflow/BoardShim.m | 81 +-- python_package/brainflow/board_shim.py | 32 + .../examples/tests/emotibit_test.py | 2 +- rust_package/brainflow/src/board_shim.rs | 4 + .../brainflow/src/ffi/board_controller.rs | 15 + src/board_controller/aavaa/aavaa_v3.cpp | 583 ++++++++++++++++++ src/board_controller/aavaa/inc/aavaa_v3.h | 53 ++ src/board_controller/board_controller.cpp | 4 + src/board_controller/board_info_getter.cpp | 5 + src/board_controller/brainflow_boards.cpp | 26 +- src/board_controller/build.cmake | 2 + src/board_controller/inc/board_info_getter.h | 2 + src/utils/inc/brainflow_constants.h | 3 +- third_party/fmt/include/fmt/format-inl.h | 2 +- tools/build.py | 24 +- 26 files changed, 882 insertions(+), 64 deletions(-) create mode 100644 src/board_controller/aavaa/aavaa_v3.cpp create mode 100644 src/board_controller/aavaa/inc/aavaa_v3.h diff --git a/cpp_package/src/board_shim.cpp b/cpp_package/src/board_shim.cpp index 44ff1c224..0fd07073e 100644 --- a/cpp_package/src/board_shim.cpp +++ b/cpp_package/src/board_shim.cpp @@ -497,6 +497,18 @@ std::vector BoardShim::get_accel_channels (int board_id, int preset) return std::vector (channels, channels + len); } +std::vector BoardShim::get_rotation_channels (int board_id, int preset) +{ + int channels[MAX_CHANNELS]; + int len = 0; + int res = ::get_rotation_channels (board_id, preset, channels, &len); + if (res != (int)BrainFlowExitCodes::STATUS_OK) + { + throw BrainFlowException ("failed to get board info", res); + } + return std::vector (channels, channels + len); +} + std::vector BoardShim::get_gyro_channels (int board_id, int preset) { int channels[MAX_CHANNELS]; diff --git a/cpp_package/src/inc/board_shim.h b/cpp_package/src/inc/board_shim.h index 3c7e94422..cb48edaf9 100644 --- a/cpp_package/src/inc/board_shim.h +++ b/cpp_package/src/inc/board_shim.h @@ -153,7 +153,14 @@ class BoardShim static std::vector get_accel_channels ( int board_id, int preset = (int)BrainFlowPresets::DEFAULT_PRESET); /** - * get row indices which hold analog data + * get row indices which hold rotation data + * @param board_id board id of your device + * @throw BrainFlowException If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR + */ + static std::vector get_rotation_channels ( + int board_id, int preset = (int)BrainFlowPresets::DEFAULT_PRESET); + /** + * get row indices which hold rotation calib data * @param board_id board id of your device * @throw BrainFlowException If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR */ diff --git a/csharp_package/brainflow/brainflow/board_controller_library.cs b/csharp_package/brainflow/brainflow/board_controller_library.cs index 99c35c4a4..92c0d8e4f 100644 --- a/csharp_package/brainflow/brainflow/board_controller_library.cs +++ b/csharp_package/brainflow/brainflow/board_controller_library.cs @@ -111,7 +111,8 @@ public enum BoardIds GALEA_SERIAL_BOARD_V4 = 49, NTL_WIFI_BOARD = 50, ANT_NEURO_EE_511_BOARD = 51, - FREEEEG128_BOARD = 52 + FREEEEG128_BOARD = 52, + AAVAA_V3_BOARD = 53 }; @@ -170,6 +171,8 @@ public static class BoardControllerLibrary64 [DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_accel_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int get_rotation_channels (int board_id, int preset, int[] channels, int[] len); + [DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_analog_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_gyro_channels (int board_id, int preset, int[] channels, int[] len); @@ -256,6 +259,8 @@ public static class BoardControllerLibrary32 [DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_accel_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int get_rotation_channels (int board_id, int preset, int[] channels, int[] len); + [DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_analog_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_gyro_channels (int board_id, int preset, int[] channels, int[] len); @@ -342,6 +347,8 @@ public static class BoardControllerLibraryLinux [DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_accel_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int get_rotation_channels (int board_id, int preset, int[] channels, int[] len); + [DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_analog_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_gyro_channels (int board_id, int preset, int[] channels, int[] len); @@ -430,6 +437,8 @@ public static class BoardControllerLibraryMac [DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_accel_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int get_rotation_channels (int board_id, int preset, int[] channels, int[] len); + [DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_analog_channels (int board_id, int preset, int[] channels, int[] len); [DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_gyro_channels (int board_id, int preset, int[] channels, int[] len); @@ -1044,6 +1053,23 @@ public static int get_accel_channels (int board_id, int preset, int[] channels, return (int)BrainFlowExitCodes.GENERAL_ERROR; } + public static int get_rotation_channels (int board_id, int preset, int[] channels, int[] len) + { + switch (PlatformHelper.get_library_environment ()) + { + case LibraryEnvironment.x64: + return BoardControllerLibrary64.get_rotation_channels (board_id, preset, channels, len); + case LibraryEnvironment.x86: + return BoardControllerLibrary32.get_rotation_channels (board_id, preset, channels, len); + case LibraryEnvironment.Linux: + return BoardControllerLibraryLinux.get_rotation_channels (board_id, preset, channels, len); + case LibraryEnvironment.MacOS: + return BoardControllerLibraryMac.get_rotation_channels (board_id, preset, channels, len); + } + + return (int)BrainFlowExitCodes.GENERAL_ERROR; + } + public static int get_analog_channels (int board_id, int preset, int[] channels, int[] len) { switch (PlatformHelper.get_library_environment ()) diff --git a/csharp_package/brainflow/brainflow/board_descr.cs b/csharp_package/brainflow/brainflow/board_descr.cs index 70dbbadb0..a48da22a5 100644 --- a/csharp_package/brainflow/brainflow/board_descr.cs +++ b/csharp_package/brainflow/brainflow/board_descr.cs @@ -22,6 +22,8 @@ public class BoardDescr [DataMember] public int[] accel_channels; [DataMember] + public int[] rotation_channels; + [DataMember] public int[] gyro_channels; [DataMember] public int[] temperature_channels; @@ -32,7 +34,7 @@ public class BoardDescr [DataMember] public int package_num_channel; [DataMember] - public int batter_channel; + public int battery_channel; [DataMember] public int timestamp_channel; [DataMember] @@ -54,6 +56,7 @@ public BoardDescr () ppg_channels = null; eda_channels = null; accel_channels = null; + rotation_channels = null; gyro_channels = null; temperature_channels = null; resistance_channels = null; diff --git a/csharp_package/brainflow/brainflow/board_shim.cs b/csharp_package/brainflow/brainflow/board_shim.cs index 16aad4a88..f714c9bf9 100644 --- a/csharp_package/brainflow/brainflow/board_shim.cs +++ b/csharp_package/brainflow/brainflow/board_shim.cs @@ -151,7 +151,7 @@ public static int get_battery_channel (int board_id, int preset = (int)BrainFlow } /// - /// get number of rows in returned by get_board_data() 2d array + /// get number of rows in returned by get_board_data() 2d array /// /// /// preset for device @@ -466,7 +466,31 @@ public static int[] get_accel_channels (int board_id, int preset = (int)BrainFlo } /// - /// get row indices which hold analog data + /// get row indices which hold rotation data + /// + /// + /// preset for device + /// array of row nums + /// If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR + public static int[] get_rotation_channels (int board_id, int preset = (int)BrainFlowPresets.DEFAULT_PRESET) + { + int[] len = new int[1]; + int[] channels = new int[512]; + int res = BoardControllerLibrary.get_rotation_channels (board_id, preset, channels, len); + if (res != (int)BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res); + } + int[] result = new int[len[0]]; + for (int i = 0; i < len[0]; i++) + { + result[i] = channels[i]; + } + return result; + } + + /// + /// get row indices which hold analog data /// /// /// preset for device diff --git a/docs/DataFormatDesc.rst b/docs/DataFormatDesc.rst index e8d8e703b..3e4cfe9fc 100644 --- a/docs/DataFormatDesc.rst +++ b/docs/DataFormatDesc.rst @@ -6,7 +6,7 @@ Data Format Description Units of Measure ------------------ -For EXG channels BrainFlow returns uV wherever possible. +For EXG channels BrainFlow returns uV wherever possible. For timestamps BrainFlow uses UNIX timestamp, this counter starts at the Unix Epoch on January 1st, 1970 at UTC. Precision is microsecond, but for some boards timestamps are generated on PC side as soon as packages were received. @@ -115,7 +115,7 @@ There is a method :code:`get_board_descr(int board_id)`. You can use it to get a .. code-block:: python - from pprint import pprint + from pprint import pprint import brainflow from brainflow.board_shim import BoardShim, BoardIds diff --git a/java_package/brainflow/src/main/java/brainflow/BoardDescr.java b/java_package/brainflow/src/main/java/brainflow/BoardDescr.java index abec44d75..66310a804 100644 --- a/java_package/brainflow/src/main/java/brainflow/BoardDescr.java +++ b/java_package/brainflow/src/main/java/brainflow/BoardDescr.java @@ -12,12 +12,13 @@ public class BoardDescr public List ppg_channels; public List eda_channels; public List accel_channels; + public List rotation_channels; public List gyro_channels; public List temperature_channels; public List resistance_channels; public List other_channels; public Integer package_num_channel; - public Integer batter_channel; + public Integer battery_channel; public Integer timestamp_channel; public Integer marker_channel; public Integer num_rows; @@ -34,6 +35,7 @@ public BoardDescr () ppg_channels = null; eda_channels = null; accel_channels = null; + rotation_channels = null; gyro_channels = null; temperature_channels = null; resistance_channels = null; diff --git a/java_package/brainflow/src/main/java/brainflow/BoardIds.java b/java_package/brainflow/src/main/java/brainflow/BoardIds.java index fb9252df3..653f61486 100644 --- a/java_package/brainflow/src/main/java/brainflow/BoardIds.java +++ b/java_package/brainflow/src/main/java/brainflow/BoardIds.java @@ -61,7 +61,8 @@ public enum BoardIds GALEA_SERIAL_BOARD_V4 (49), NTL_WIFI_BOARD (50), ANT_NEURO_EE_511_BOARD (51), - FREEEEG128_BOARD (52); + FREEEEG128_BOARD (52), + AAVAA_V3_BOARD(53); private final int board_id; private static final Map bi_map = new HashMap (); diff --git a/java_package/brainflow/src/main/java/brainflow/BoardShim.java b/java_package/brainflow/src/main/java/brainflow/BoardShim.java index a55e25f29..064c6acb0 100644 --- a/java_package/brainflow/src/main/java/brainflow/BoardShim.java +++ b/java_package/brainflow/src/main/java/brainflow/BoardShim.java @@ -80,6 +80,8 @@ int get_current_board_data (int num_samples, int preset, double[] data_buf, int[ int get_accel_channels (int board_id, int preset, int[] accel_channels, int[] len); + int get_rotation_channels (int board_id, int preset, int[] rotation_channels, int[] len); + int get_analog_channels (int board_id, int preset, int[] analog_channels, int[] len); int get_gyro_channels (int board_id, int preset, int[] gyro_channels, int[] len); @@ -1418,9 +1420,9 @@ public String config_board (String config) throws BrainFlowError /** * start streaming thread, store data in internal ringbuffer and stream them * from brainflow at the same time - * + * * @param buffer_size size of internal ringbuffer - * + * * @param streamer_params supported vals: "file://%file_name%:w", * "file://%file_name%:a", * "streaming_board://%multicast_group_ip%:%port%". Range diff --git a/julia_package/brainflow/src/board_shim.jl b/julia_package/brainflow/src/board_shim.jl index dd3cf3f38..195f83661 100644 --- a/julia_package/brainflow/src/board_shim.jl +++ b/julia_package/brainflow/src/board_shim.jl @@ -57,6 +57,7 @@ export BrainFlowInputParams NTL_WIFI_BOARD = 50 ANT_NEURO_EE_511_BOARD = 51 FREEEEG128_BOARD = 52 + AAVAA_V3_BOARD = 53 end @@ -188,6 +189,7 @@ channel_function_names = ( :get_eda_channels, :get_ppg_channels, :get_accel_channels, + :get_rotation_channels, :get_analog_channels, :get_gyro_channels, :get_other_channels, @@ -294,7 +296,7 @@ end end num_rows = get_num_rows(board_shim.master_board_id, preset) val = Vector{Float64}(undef, num_rows * data_size) - ccall((:get_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Cint, Ptr{UInt8}), + ccall((:get_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Cint, Ptr{UInt8}), data_size, Int32(preset), val, board_shim.board_id, board_shim.input_json) value = transpose(reshape(val, (data_size, num_rows))) return value @@ -304,7 +306,7 @@ end data_size = get_board_data_count(board_shim, preset) num_rows = get_num_rows(board_shim.master_board_id, preset) val = Vector{Float64}(undef, num_rows * data_size) - ccall((:get_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Cint, Ptr{UInt8}), + ccall((:get_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Cint, Ptr{UInt8}), data_size, Int32(preset), val, board_shim.board_id, board_shim.input_json) value = transpose(reshape(val, (data_size, num_rows))) return value @@ -314,7 +316,7 @@ end data_size = Vector{Cint}(undef, 1) num_rows = get_num_rows(board_shim.master_board_id, preset) val = Vector{Float64}(undef, num_rows * num_samples) - ccall((:get_current_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Ptr{Cint}, Cint, Ptr{UInt8}), + ccall((:get_current_board_data, BOARD_CONTROLLER_INTERFACE), Cint, (Cint, Cint, Ptr{Float64}, Ptr{Cint}, Cint, Ptr{UInt8}), num_samples, Int32(preset), val, data_size, board_shim.board_id, board_shim.input_json) value = transpose(reshape(val[1:data_size[1] * num_rows], (data_size[1], num_rows))) return value diff --git a/matlab_package/brainflow/BoardIds.m b/matlab_package/brainflow/BoardIds.m index 88694ba2d..7d817cc72 100644 --- a/matlab_package/brainflow/BoardIds.m +++ b/matlab_package/brainflow/BoardIds.m @@ -55,5 +55,6 @@ NTL_WIFI_BOARD(50) ANT_NEURO_EE_511_BOARD(51) FREEEEG128_BOARD(52) + AAVAA_V3_BOARD(53) end end \ No newline at end of file diff --git a/matlab_package/brainflow/BoardShim.m b/matlab_package/brainflow/BoardShim.m index 6e38bc556..0c1d2772f 100644 --- a/matlab_package/brainflow/BoardShim.m +++ b/matlab_package/brainflow/BoardShim.m @@ -7,7 +7,7 @@ end methods(Static) - + function lib_name = load_lib() if ispc if not(libisloaded('BoardController')) @@ -28,13 +28,13 @@ error('OS not supported!') end end - + function check_ec(ec, task_name) if (ec ~= int32(BrainFlowExitCodes.STATUS_OK)) error('Non zero ec: %d, for task: %s', ec, task_name) end end - + function release_all_sessions() % release all sessions task_name = 'release_all_sessions'; @@ -73,7 +73,7 @@ function disable_board_logger() % disable logger BoardShim.set_log_level(int32(6)) end - + function log_message(log_level, message) % write message to BoardShim logger task_name = 'log_message_board_controller'; @@ -81,7 +81,7 @@ function log_message(log_level, message) exit_code = calllib(lib_name, task_name, log_level, message); BoardShim.check_ec(exit_code, task_name); end - + function sampling_rate = get_sampling_rate(board_id, preset) % get sampling rate for provided board id task_name = 'get_sampling_rate'; @@ -91,7 +91,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); sampling_rate = res.value; end - + function package_num_channel = get_package_num_channel(board_id, preset) % get package num channel for provided board id task_name = 'get_package_num_channel'; @@ -102,7 +102,7 @@ function log_message(log_level, message) % Matlab counts array elements from 1 while BrainFlow Core counts from 0% package_num_channel = res.value + 1; end - + function marker_channel = get_marker_channel(board_id, preset) % get marker channel for provided board id task_name = 'get_marker_channel'; @@ -122,7 +122,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); battery_channel = res.value + 1; end - + function num_rows = get_num_rows(board_id, preset) % get num rows for provided board id task_name = 'get_num_rows'; @@ -132,7 +132,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); num_rows = res.value; end - + function timestamp_channel = get_timestamp_channel(board_id, preset) % get timestamp channel for provided board id task_name = 'get_timestamp_channel'; @@ -142,7 +142,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); timestamp_channel = res.value + 1; end - + function board_descr = get_board_descr(board_id, preset) % get board descr for provided board id task_name = 'get_board_descr'; @@ -153,7 +153,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); board_descr = jsondecode(board_descr); end - + function eeg_names = get_eeg_names(board_id, preset) % get eeg names for provided board id task_name = 'get_eeg_names'; @@ -164,7 +164,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); eeg_names = split(eeg_names, ','); end - + function presets = get_board_presets(board_id) % get supported presets task_name = 'get_board_presets'; @@ -174,9 +174,9 @@ function log_message(log_level, message) exit_code = calllib(lib_name, task_name, board_id, data, num_presets); BoardShim.check_ec(exit_code, task_name); presets = data.Value(1,1:num_presets.Value); - + end - + function version = get_version() % get version task_name = 'get_version_board_controller'; @@ -186,7 +186,7 @@ function log_message(log_level, message) [exit_code, version] = calllib(lib_name, task_name, blanks(64), 64, 64); BoardShim.check_ec(exit_code, task_name); end - + function device_name = get_device_name(board_id, preset) % get device name for provided board id task_name = 'get_device_name'; @@ -196,7 +196,7 @@ function log_message(log_level, message) [exit_code, device_name] = calllib(lib_name, task_name, board_id, preset, blanks(4096), 4096); BoardShim.check_ec(exit_code, task_name); end - + function eeg_channels = get_eeg_channels(board_id, preset) % get eeg channels for provided board id task_name = 'get_eeg_channels'; @@ -207,7 +207,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); eeg_channels = data.Value(1,1:num_channels.Value) + 1; end - + function exg_channels = get_exg_channels(board_id, preset) % get exg channels for provided board id task_name = 'get_exg_channels'; @@ -218,7 +218,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); exg_channels = data.Value(1,1:num_channels.Value) + 1; end - + function emg_channels = get_emg_channels(board_id, preset) % get emg channels for provided board id task_name = 'get_emg_channels'; @@ -229,7 +229,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); emg_channels = data.Value(1,1:num_channels.Value) + 1; end - + function ecg_channels = get_ecg_channels(board_id, preset) % get ecg channels for provided board id task_name = 'get_ecg_channels'; @@ -240,7 +240,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); ecg_channels = data.Value(1,1:num_channels.Value) + 1; end - + function eog_channels = get_eog_channels(board_id, preset) % get eog channels for provided board id task_name = 'get_eog_channels'; @@ -251,7 +251,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); eog_channels = data.Value(1,1:num_channels.Value) + 1; end - + function ppg_channels = get_ppg_channels(board_id, preset) % get ppg channels for provided board id task_name = 'get_ppg_channels'; @@ -262,7 +262,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); ppg_channels = data.Value(1,1:num_channels.Value) + 1; end - + function eda_channels = get_eda_channels(board_id, preset) % get eda channels for provided board id task_name = 'get_eda_channels'; @@ -273,7 +273,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); eda_channels = data.Value(1,1:num_channels.Value) + 1; end - + function accel_channels = get_accel_channels(board_id, preset) % get accel channels for provided board id task_name = 'get_accel_channels'; @@ -284,7 +284,18 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); accel_channels = data.Value(1,1:num_channels.Value) + 1; end - + + function rotation_channels = get_rotation_channels(board_id, preset) + % get accel channels for provided board id + task_name = 'get_rotation_channels'; + lib_name = BoardShim.load_lib(); + num_channels = libpointer('int32Ptr', 0); + data = libpointer('int32Ptr', zeros(1, 512)); + exit_code = calllib(lib_name, task_name, board_id, preset, data, num_channels); + BoardShim.check_ec(exit_code, task_name); + rotation_channels = data.Value(1,1:num_channels.Value) + 1; + end + function analog_channels = get_analog_channels(board_id, preset) % get analog channels for provided board id task_name = 'get_analog_channels'; @@ -295,7 +306,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); analog_channels = data.Value(1,1:num_channels.Value) + 1; end - + function other_channels = get_other_channels(board_id, preset) % get other channels for provided board id task_name = 'get_other_channels'; @@ -306,7 +317,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); other_channels = data.Value(1,1:num_channels.Value) + 1; end - + function temperature_channels = get_temperature_channels(board_id, preset) % get temperature channels for provided board id task_name = 'get_temperature_channels'; @@ -317,7 +328,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); temperature_channels = data.Value(1,1:num_channels.Value) + 1; end - + function resistance_channels = get_resistance_channels(board_id, preset) % get resistance channels for provided board id task_name = 'get_resistance_channels'; @@ -328,7 +339,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); resistance_channels = data.Value(1,1:num_channels.Value) + 1; end - + function magnetometer_channels = get_magnetometer_channels(board_id, preset) % get magnetometer channels for provided board id task_name = 'get_magnetometer_channels'; @@ -339,7 +350,7 @@ function log_message(log_level, message) BoardShim.check_ec(exit_code, task_name); magnetometer_channels = data.Value(1,1:num_channels.Value) + 1; end - + end methods @@ -374,7 +385,7 @@ function prepare_session(obj) [exit_code, tmp, response] = calllib(lib_name, task_name, config, blanks(4096), 4096, obj.board_id, obj.input_params_json); BoardShim.check_ec(exit_code, task_name); end - + function add_streamer(obj, streamer, preset) % add streamer task_name = 'add_streamer'; @@ -384,7 +395,7 @@ function add_streamer(obj, streamer, preset) [exit_code, tmp] = calllib(lib_name, task_name, streamer, preset, obj.board_id, obj.input_params_json); BoardShim.check_ec(exit_code, task_name); end - + function delete_streamer(obj, streamer, preset) % delete streamer task_name = 'delete_streamer'; @@ -418,7 +429,7 @@ function release_session(obj) exit_code = calllib(lib_name, task_name, obj.board_id, obj.input_params_json); BoardShim.check_ec(exit_code, task_name); end - + function insert_marker(obj, value, preset) % insert marker task_name = 'insert_marker'; @@ -467,7 +478,7 @@ function insert_marker(obj, value, preset) BoardShim.check_ec(exit_code, task_name); data_buf = transpose(reshape(data.Value(1,1:data_count.Value * num_rows), [data_count.Value, num_rows])); end - + function prepared = is_prepared(obj) % check if brainflow session prepared task_name = 'is_prepared'; @@ -477,7 +488,7 @@ function insert_marker(obj, value, preset) BoardShim.check_ec(exit_code, task_name); prepared = boolean(res.value); end - + end - + end \ No newline at end of file diff --git a/python_package/brainflow/board_shim.py b/python_package/brainflow/board_shim.py index 8888ee99e..a1ebb6e19 100644 --- a/python_package/brainflow/board_shim.py +++ b/python_package/brainflow/board_shim.py @@ -71,6 +71,7 @@ class BoardIds(enum.IntEnum): NTL_WIFI_BOARD = 50 #: ANT_NEURO_EE_511_BOARD = 51 #: FREEEEG128_BOARD = 52 #: + AAVAA_V3_BOARD = 53 #: class IpProtocolTypes(enum.IntEnum): @@ -475,6 +476,15 @@ def __init__(self): ndpointer(ctypes.c_int32) ] + self.get_rotation_channels = self.lib.get_rotation_channels + self.get_rotation_channels.restype = ctypes.c_int + self.get_rotation_channels.argtypes = [ + ctypes.c_int, + ctypes.c_int, + ndpointer(ctypes.c_int32), + ndpointer(ctypes.c_int32) + ] + self.get_analog_channels = self.lib.get_analog_channels self.get_analog_channels.restype = ctypes.c_int self.get_analog_channels.argtypes = [ @@ -999,6 +1009,28 @@ def get_accel_channels(cls, board_id: int, preset: int = BrainFlowPresets.DEFAUL result = accel_channels.tolist()[0:num_channels[0]] return result + @classmethod + def get_rotation_channels(cls, board_id: int, preset: int = BrainFlowPresets.DEFAULT_PRESET) -> List[int]: + """get list of rotation channels in resulting data table for a board + + :param board_id: Board Id + :type board_id: int + :param preset: preset + :type preset: int + :return: list of rotation channels in returned numpy array + :rtype: List[int] + :raises BrainFlowError: If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR + """ + + num_channels = numpy.zeros(1).astype(numpy.int32) + rotation_channels = numpy.zeros(512).astype(numpy.int32) + + res = BoardControllerDLL.get_instance().get_rotation_channels(board_id, preset, rotation_channels, num_channels) + if res != BrainFlowExitCodes.STATUS_OK.value: + raise BrainFlowError('unable to request info about this board', res) + result = rotation_channels.tolist()[0:num_channels[0]] + return result + @classmethod def get_analog_channels(cls, board_id: int, preset: int = BrainFlowPresets.DEFAULT_PRESET) -> List[int]: """get list of analog channels in resulting data table for a board diff --git a/python_package/examples/tests/emotibit_test.py b/python_package/examples/tests/emotibit_test.py index 4c0eaba03..98970751e 100644 --- a/python_package/examples/tests/emotibit_test.py +++ b/python_package/examples/tests/emotibit_test.py @@ -12,7 +12,7 @@ def main(): presets = BoardShim.get_board_presets(board_id) print (presets) - + board = BoardShim(board_id, params) board.prepare_session() board.start_stream() diff --git a/rust_package/brainflow/src/board_shim.rs b/rust_package/brainflow/src/board_shim.rs index 8c975c01f..e4b599760 100644 --- a/rust_package/brainflow/src/board_shim.rs +++ b/rust_package/brainflow/src/board_shim.rs @@ -493,6 +493,10 @@ gen_vec_fn!( accel_channels, "Get list of accel channels in resulting data table for a board." ); +gen_vec_fn!( + rotation_channels, + "Get list of rotation channels in resulting data table for a board." +); gen_vec_fn!( gyro_channels, "Get list of gyro channels in resulting data table for a board." diff --git a/rust_package/brainflow/src/ffi/board_controller.rs b/rust_package/brainflow/src/ffi/board_controller.rs index 88ca31bca..1a6db0788 100644 --- a/rust_package/brainflow/src/ffi/board_controller.rs +++ b/rust_package/brainflow/src/ffi/board_controller.rs @@ -125,6 +125,21 @@ extern "C" { len: *mut ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } +extern "C" { + pub fn get_rotaiton_channels( + board_id: ::std::os::raw::c_int, + preset: ::std::os::raw::c_int, + rotation_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_rotaiton_calib_channel( + board_id: ::std::os::raw::c_int, + preset: ::std::os::raw::c_int, + get_rotaiton_calib_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} extern "C" { pub fn get_analog_channels( board_id: ::std::os::raw::c_int, diff --git a/src/board_controller/aavaa/aavaa_v3.cpp b/src/board_controller/aavaa/aavaa_v3.cpp new file mode 100644 index 000000000..5793e6783 --- /dev/null +++ b/src/board_controller/aavaa/aavaa_v3.cpp @@ -0,0 +1,583 @@ +#include + +#include "aavaa_v3.h" +#include "custom_cast.h" +#include "get_dll_dir.h" +#include "timestamp.h" + +#define START_BYTE 0xA0 +#define END_BYTE 0xC0 + +#define AAVAA3_WRITE_CHAR "6e400002-c352-11e5-953d-0002a5d5c51b" +#define AAVAA3_NOTIFY_CHAR "6e400003-c352-11e5-953d-0002a5d5c51b" + + +void aavaa_adapter_1_on_scan_start (simpleble_adapter_t adapter, void *board) +{ + ((AAVAAv3 *)(board))->adapter_1_on_scan_start (adapter); +} + +void aavaa_adapter_1_on_scan_stop (simpleble_adapter_t adapter, void *board) +{ + ((AAVAAv3 *)(board))->adapter_1_on_scan_stop (adapter); +} + +void aavaa_adapter_1_on_scan_found ( + simpleble_adapter_t adapter, simpleble_peripheral_t peripheral, void *board) +{ + ((AAVAAv3 *)(board))->adapter_1_on_scan_found (adapter, peripheral); +} + +void aavaa_read_notifications (simpleble_uuid_t service, simpleble_uuid_t characteristic, + uint8_t *data, size_t size, void *board) +{ + ((AAVAAv3 *)(board))->read_data (service, characteristic, data, size); +} + +AAVAAv3::AAVAAv3 (struct BrainFlowInputParams params) + : BLELibBoard ((int)BoardIds::AAVAA_V3_BOARD, params) +{ + initialized = false; + aavaa_adapter = NULL; + aavaa_peripheral = NULL; + is_streaming = false; + start_command = "\x01\x62"; + stop_command = "\x01\x39"; +} + +AAVAAv3::~AAVAAv3 () +{ + skip_logs = true; + release_session (); +} + +int AAVAAv3::prepare_session () +{ + if (initialized) + { + safe_logger (spdlog::level::info, "Session is already prepared"); + return (int)BrainFlowExitCodes::STATUS_OK; + } + if (params.timeout < 1) + { + params.timeout = 5; + } + safe_logger (spdlog::level::info, "Use timeout for discovery: {}", params.timeout); + if (!init_dll_loader ()) + { + safe_logger (spdlog::level::err, "Failed to init dll_loader"); + return (int)BrainFlowExitCodes::GENERAL_ERROR; + } + size_t adapter_count = simpleble_adapter_get_count (); + if (adapter_count == 0) + { + safe_logger (spdlog::level::err, "No BLE adapters found"); + return (int)BrainFlowExitCodes::UNABLE_TO_OPEN_PORT_ERROR; + } + + aavaa_adapter = simpleble_adapter_get_handle (0); + if (aavaa_adapter == NULL) + { + safe_logger (spdlog::level::err, "Adapter is NULL"); + return (int)BrainFlowExitCodes::UNABLE_TO_OPEN_PORT_ERROR; + } + + simpleble_adapter_set_callback_on_scan_start ( + aavaa_adapter, ::aavaa_adapter_1_on_scan_start, (void *)this); + simpleble_adapter_set_callback_on_scan_stop ( + aavaa_adapter, ::aavaa_adapter_1_on_scan_stop, (void *)this); + simpleble_adapter_set_callback_on_scan_found ( + aavaa_adapter, ::aavaa_adapter_1_on_scan_found, (void *)this); + +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + + if (!simpleble_adapter_is_bluetooth_enabled ()) + { + safe_logger (spdlog::level::warn, "Probably bluetooth is disabled."); + // dont throw an exception because of this + // https://github.com/OpenBluetoothToolbox/SimpleBLE/issues/115 + } + + simpleble_adapter_scan_start (aavaa_adapter); + int res = (int)BrainFlowExitCodes::STATUS_OK; + std::unique_lock lk (m); + auto sec = std::chrono::seconds (1); + if (cv.wait_for (lk, params.timeout * sec, [this] { return this->aavaa_peripheral != NULL; })) + { + safe_logger (spdlog::level::info, "Found AAVAAv3 device"); + } + else + { + safe_logger (spdlog::level::err, "Failed to find AAVAAv3 Device"); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; + } + simpleble_adapter_scan_stop (aavaa_adapter); + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + // for safety + for (int i = 0; i < 3; i++) + { + if (simpleble_peripheral_connect (aavaa_peripheral) == SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::info, "Connected to AAVAAv3 Device"); + res = (int)BrainFlowExitCodes::STATUS_OK; + break; + } + else + { + safe_logger (spdlog::level::err, "Failed to connect to AAVAAv3 Device"); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + } + } + } + else + { +// https://github.com/OpenBluetoothToolbox/SimpleBLE/issues/26#issuecomment-955606799 +#ifdef __linux__ + usleep (1000000); +#endif + } + + int num_chars_found = 0; + + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + size_t services_count = simpleble_peripheral_services_count (aavaa_peripheral); + for (size_t i = 0; i < services_count; i++) + { + simpleble_service_t service; + if (simpleble_peripheral_services_get (aavaa_peripheral, i, &service) != + SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to get service"); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; + } + + safe_logger (spdlog::level::trace, "found servce {}", service.uuid.value); + for (size_t j = 0; j < service.characteristic_count; j++) + { + safe_logger (spdlog::level::trace, "found characteristic {}", + service.characteristics[j].uuid.value); + + if (strcmp (service.characteristics[j].uuid.value, + AAVAA3_WRITE_CHAR) == 0) // Write Characteristics + { + write_characteristics = std::pair ( + service.uuid, service.characteristics[j].uuid); + num_chars_found++; + } + if (strcmp (service.characteristics[j].uuid.value, + AAVAA3_NOTIFY_CHAR) == 0) // Notification Characteristics + { + if (simpleble_peripheral_notify (aavaa_peripheral, service.uuid, + service.characteristics[j].uuid, ::aavaa_read_notifications, + (void *)this) == SIMPLEBLE_SUCCESS) + { + notified_characteristics = std::pair ( + service.uuid, service.characteristics[j].uuid); + num_chars_found++; + } + else + { + safe_logger (spdlog::level::err, "Failed to notify for {} {}", + service.uuid.value, service.characteristics[j].uuid.value); + res = (int)BrainFlowExitCodes::GENERAL_ERROR; + } + } + } + } + } + + if ((res == (int)BrainFlowExitCodes::STATUS_OK) && (num_chars_found == 2)) + { + initialized = true; + } + else + { + release_session (); + } + return res; +} + +int AAVAAv3::start_stream (int buffer_size, const char *streamer_params) +{ + if (!initialized) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + if (is_streaming) + { + return (int)BrainFlowExitCodes::STREAM_ALREADY_RUN_ERROR; + } + + int res = prepare_for_acquisition (buffer_size, streamer_params); + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + res = send_command (start_command); + } + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + is_streaming = true; + } + + return res; +} + +int AAVAAv3::stop_stream () +{ + if (aavaa_peripheral == NULL) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + int res = (int)BrainFlowExitCodes::STATUS_OK; + if (is_streaming) + { + res = send_command (stop_command); + } + else + { + res = (int)BrainFlowExitCodes::STREAM_THREAD_IS_NOT_RUNNING; + } + is_streaming = false; + return res; +} + +int AAVAAv3::release_session () +{ + if (initialized) + { + // repeat it multiple times, failure here may lead to a crash + for (int i = 0; i < 2; i++) + { + stop_stream (); + // need to wait for notifications to stop triggered before unsubscribing, otherwise + // macos fails inside simpleble with timeout +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + if (simpleble_peripheral_unsubscribe (aavaa_peripheral, notified_characteristics.first, + notified_characteristics.second) != SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to unsubscribe for {} {}", + notified_characteristics.first.value, notified_characteristics.second.value); + } + else + { + safe_logger (spdlog::level::trace, "unsubscribed successfully."); + break; + } + } + safe_logger (spdlog::level::trace, "freeing packages."); + free_packages (); + initialized = false; + } + if (aavaa_peripheral != NULL) + { + safe_logger (spdlog::level::info, "peripheral is not NULL."); + bool is_connected = false; + if (simpleble_peripheral_is_connected (aavaa_peripheral, &is_connected) == + SIMPLEBLE_SUCCESS) + { + if (is_connected) + { + simpleble_peripheral_disconnect (aavaa_peripheral); + } + } + simpleble_peripheral_release_handle (aavaa_peripheral); + aavaa_peripheral = NULL; + } + if (aavaa_adapter != NULL) + { + safe_logger (spdlog::level::info, "adapter is not NULL."); + simpleble_adapter_release_handle (aavaa_adapter); + aavaa_adapter = NULL; + } + safe_logger (spdlog::level::trace, "released successfully."); + return (int)BrainFlowExitCodes::STATUS_OK; +} + +int AAVAAv3::config_board (std::string config, std::string &response) +{ + safe_logger (spdlog::level::trace, "config requested: {}", config); + if (!initialized) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + if (config.empty ()) + { + return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR; + } + + int res = (int)BrainFlowExitCodes::STATUS_OK; + + if (config == "w") + { + safe_logger (spdlog::level::trace, "device status was requested {}", device_status); + response = device_status; + device_status = ""; + return res; + } + + if ((config[0] == 'z') || (config[0] == 'Z')) + { + bool was_streaming = is_streaming; + if (was_streaming) + { + safe_logger (spdlog::level::trace, + "disabling streaming to turn on or off impedance, stop command is: {}", + stop_command.c_str ()); + res = send_command (stop_command); + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + is_streaming = false; + } + } + if (config[0] == 'z') + { + start_command = "z"; + stop_command = "Z"; + } + else if (config[0] == 'Z') + { + start_command = "b"; + stop_command = "s"; + } + if (was_streaming) + { + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + safe_logger (spdlog::level::trace, + "enabling streaming to turn on or off impedance, start command is: {}", + start_command.c_str ()); + res = send_command (start_command); + } + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + is_streaming = true; + } + } + } + else + { + res = send_command (config); + } + return res; +} + +int AAVAAv3::send_command (std::string config) +{ + if (!initialized) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + if (config.empty ()) + { + return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR; + } + uint8_t *command = new uint8_t[config.size ()]; + memcpy (command, config.c_str (), config.size ()); + if (simpleble_peripheral_write_command (aavaa_peripheral, write_characteristics.first, + write_characteristics.second, command, config.size ()) != SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to send command {} to device", config.c_str ()); + delete[] command; + return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR; + } + else + { + safe_logger ( + spdlog::level::trace, "successfully sent command {} to device", config.c_str ()); + } + delete[] command; + return (int)BrainFlowExitCodes::STATUS_OK; +} + +void AAVAAv3::adapter_1_on_scan_start (simpleble_adapter_t adapter) +{ + safe_logger (spdlog::level::trace, "Scan started"); +} + +void AAVAAv3::adapter_1_on_scan_stop (simpleble_adapter_t adapter) +{ + safe_logger (spdlog::level::trace, "Scan stopped"); +} + +void AAVAAv3::adapter_1_on_scan_found ( + simpleble_adapter_t adapter, simpleble_peripheral_t peripheral) +{ + char *peripheral_identified = simpleble_peripheral_identifier (peripheral); + char *peripheral_address = simpleble_peripheral_address (peripheral); + bool found = false; + if (!params.mac_address.empty ()) + { + if (strcmp (peripheral_address, params.mac_address.c_str ()) == 0) + { + found = true; + } + } + else + { + if (!params.serial_number.empty ()) + { + if (strcmp (peripheral_identified, params.serial_number.c_str ()) == 0) + { + found = true; + } + } + else + { + if (strncmp (peripheral_identified, "AAVAAv3", 8) == 0) + { + found = true; + } + } + } + + safe_logger (spdlog::level::trace, "address {}", peripheral_address); + simpleble_free (peripheral_address); + safe_logger (spdlog::level::trace, "identifier {}", peripheral_identified); + simpleble_free (peripheral_identified); + + if (found) + { + { + std::lock_guard lk (m); + aavaa_peripheral = peripheral; + } + cv.notify_one (); + } + else + { + simpleble_peripheral_release_handle (peripheral); + } +} + +void AAVAAv3::read_data ( + simpleble_uuid_t service, simpleble_uuid_t characteristic, uint8_t *data, size_t size) +{ + safe_logger (spdlog::level::trace, "received {} number of bytes", size); + + if (!is_streaming) + { + if (data[1] == 64) + { // when the first byte is @ + std::string temp (reinterpret_cast (data), size); + device_status = temp.substr (1); + safe_logger (spdlog::level::trace, "received a status string {} ", device_status); + } + else + { + safe_logger (spdlog::level::trace, "received a string with start byte {} {} {} {} {}", + data[0], data[1], data[2], data[3], data[4]); + } + return; + } + + int num_rows = board_descr["default"]["num_rows"]; + + std::vector eeg_channels = board_descr["default"]["eeg_channels"]; + + if (size == 244) + { + data += 3; + size -= 3; + Incoming_BLE_Data_Buffer.insert (Incoming_BLE_Data_Buffer.end (), data, data + size); + } + else if (size > 1) + { + ++data; + --size; + Incoming_BLE_Data_Buffer.insert (Incoming_BLE_Data_Buffer.end (), data, data + size); + } + + while (Incoming_BLE_Data_Buffer.size () >= SIZE_OF_DATA_FRAME) + { + if (Incoming_BLE_Data_Buffer[0] != START_BYTE) + { + Incoming_BLE_Data_Buffer.pop_front (); // discard data, we have half a frame here + continue; + } + + uint8_t *data_frame = new uint8_t[SIZE_OF_DATA_FRAME]; + for (int i = 0; i < SIZE_OF_DATA_FRAME; ++i) + { + data_frame[i] = Incoming_BLE_Data_Buffer.front (); + Incoming_BLE_Data_Buffer.pop_front (); + } + + if (data_frame[SIZE_OF_DATA_FRAME - 1] != END_BYTE) + { + safe_logger ( + spdlog::level::warn, "Wrong End Byte: {}", data_frame[SIZE_OF_DATA_FRAME - 1]); + continue; + } + + double *package = new double[num_rows]; + for (int i = 0; i < num_rows; i++) + { + package[i] = 0.0; + } + + // package num + package[board_descr["default"]["package_num_channel"].get ()] = (double)data_frame[1]; + + // eeg + for (unsigned int i = 0; i < eeg_channels.size (); i++) + { + // all the eeg_channels are 4 bytes and we skip the START byte and package number byte + float f_value; + std::memcpy (&f_value, data_frame + 2 + 4 * i, sizeof (f_value)); + double d_value = static_cast (f_value); + package[eeg_channels[i]] = EEG_SCALE * d_value; + } + + package[board_descr["default"]["rotation_channels"][0].get ()] = + IMU_SCALE * cast_16bit_to_int32 (data_frame + 34); + package[board_descr["default"]["rotation_channels"][1].get ()] = + IMU_SCALE * cast_16bit_to_int32 (data_frame + 36); + package[board_descr["default"]["rotation_channels"][2].get ()] = + IMU_SCALE * cast_16bit_to_int32 (data_frame + 38); + + // battery byte + package[board_descr["default"]["battery_channel"].get ()] = (double)data_frame[40]; + + // imu status byte + package[board_descr["default"]["other_channels"][0].get ()] = + (double)data_frame[41]; + + // timestamp + try + { + package[board_descr["default"]["other_channels"][1].get ()] = + *reinterpret_cast (data_frame + 42) * + TIMESTAMP_SCALE; // get_timestamp (); + } + catch (const std::exception &e) + { + std::string error_message = std::string ("Exception occurred: ") + e.what (); + safe_logger (spdlog::level::warn, error_message); + } + + package[board_descr["default"]["timestamp_channel"].get ()] = get_timestamp (); + + push_package (package); + delete[] package; + delete[] data_frame; + } +} diff --git a/src/board_controller/aavaa/inc/aavaa_v3.h b/src/board_controller/aavaa/inc/aavaa_v3.h new file mode 100644 index 000000000..2bb05e7fe --- /dev/null +++ b/src/board_controller/aavaa/inc/aavaa_v3.h @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include "ble_lib_board.h" +#include "board.h" +#include "board_controller.h" + + +class AAVAAv3 : public BLELibBoard +{ +public: + AAVAAv3 (struct BrainFlowInputParams params); + ~AAVAAv3 (); + + int prepare_session (); + int start_stream (int buffer_size, const char *streamer_params); + int stop_stream (); + int release_session (); + int config_board (std::string config, std::string &response); + int send_command (std::string config); + + void adapter_1_on_scan_start (simpleble_adapter_t adapter); + void adapter_1_on_scan_stop (simpleble_adapter_t adapter); + void adapter_1_on_scan_found (simpleble_adapter_t adapter, simpleble_peripheral_t peripheral); + void read_data ( + simpleble_uuid_t service, simpleble_uuid_t characteristic, uint8_t *data, size_t size); + std::deque Incoming_BLE_Data_Buffer; + std::string device_status; + +protected: + const double TIMESTAMP_SCALE = (double)(10. / 1000000.); // 10 us + const double IMU_SCALE = (double)(1. / 100.); + const int Ring_Buffer_Max_Size = 244 * 5; + const int SIZE_OF_DATA_FRAME = 47; + const double ADS1299_Vref = 4.5; // reference voltage for ADC in ADS1299 + const double ADS1299_gain = 12.; // assumed gain setting for ADS1299 + const double EEG_SCALE = ADS1299_Vref / float ((pow (2, 23) - 1)) / ADS1299_gain * 1000000.0; + + volatile simpleble_adapter_t aavaa_adapter; + volatile simpleble_peripheral_t aavaa_peripheral; + bool initialized; + bool is_streaming; + std::mutex m; + std::condition_variable cv; + std::pair notified_characteristics; + std::pair write_characteristics; + std::string start_command; + std::string stop_command; +}; diff --git a/src/board_controller/board_controller.cpp b/src/board_controller/board_controller.cpp index 0decd8064..535f55aae 100644 --- a/src/board_controller/board_controller.cpp +++ b/src/board_controller/board_controller.cpp @@ -14,6 +14,7 @@ #include #include +#include "aavaa_v3.h" #include "ant_neuro.h" #include "board.h" #include "board_controller.h" @@ -267,6 +268,9 @@ int prepare_session (int board_id, const char *json_brainflow_input_params) case BoardIds::NTL_WIFI_BOARD: board = std::shared_ptr (new NtlWifi (params)); break; + case BoardIds::AAVAA_V3_BOARD: + board = std::shared_ptr (new AAVAAv3 (params)); + break; default: return (int)BrainFlowExitCodes::UNSUPPORTED_BOARD_ERROR; } diff --git a/src/board_controller/board_info_getter.cpp b/src/board_controller/board_info_getter.cpp index 7a87dbb51..4ddd5a1e9 100644 --- a/src/board_controller/board_info_getter.cpp +++ b/src/board_controller/board_info_getter.cpp @@ -166,6 +166,11 @@ int get_accel_channels (int board_id, int preset, int *accel_channels, int *len) return get_array_value (board_id, preset, "accel_channels", accel_channels, len); } +int get_rotation_channels (int board_id, int preset, int *rotation_channels, int *len) +{ + return get_array_value (board_id, preset, "rotation_channels", rotation_channels, len); +} + int get_analog_channels (int board_id, int preset, int *analog_channels, int *len) { return get_array_value (board_id, preset, "analog_channels", analog_channels, len); diff --git a/src/board_controller/brainflow_boards.cpp b/src/board_controller/brainflow_boards.cpp index cfbc8859a..f6e0a2bb6 100644 --- a/src/board_controller/brainflow_boards.cpp +++ b/src/board_controller/brainflow_boards.cpp @@ -70,7 +70,8 @@ BrainFlowBoards::BrainFlowBoards() {"49", json::object()}, {"50", json::object()}, {"51", json::object()}, - {"52", json::object()} + {"52", json::object()}, + {"53", json::object()} } }}; @@ -213,7 +214,7 @@ BrainFlowBoards::BrainFlowBoards() {"other_channels", {8, 9, 10, 11, 12, 13, 14}}, {"resistance_channels", {18, 19, 20, 21, 22}} }; - brainflow_boards_json["boards"]["5"]["default"] = + brainflow_boards_json["boards"]["5"]["default"] = { {"name", "CytonWifi"}, {"sampling_rate", 1000}, @@ -229,7 +230,7 @@ BrainFlowBoards::BrainFlowBoards() {"analog_channels", {19, 20, 21}}, {"other_channels", {12, 13, 14, 15, 16, 17, 18}} }; - brainflow_boards_json["boards"]["6"]["default"] = + brainflow_boards_json["boards"]["6"]["default"] = { {"name", "CytonDaisyWifi"}, {"sampling_rate", 1000}, @@ -245,7 +246,7 @@ BrainFlowBoards::BrainFlowBoards() {"analog_channels", {27, 28, 29}}, {"other_channels", {20, 21, 22, 23, 24, 25, 26}} }; - brainflow_boards_json["boards"]["7"]["default"] = + brainflow_boards_json["boards"]["7"]["default"] = { {"name", "BrainBit"}, {"sampling_rate", 250}, @@ -990,6 +991,23 @@ BrainFlowBoards::BrainFlowBoards() {"emg_channels", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128}}, {"ecg_channels", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128}} }; + brainflow_boards_json["boards"]["53"]["default"] = + { + {"name", "AAVAA V3"}, + {"sampling_rate", 50}, + {"package_num_channel", 0}, + {"timestamp_channel", 15}, + {"marker_channel", 16}, + {"num_rows", 17}, + {"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}, + {"eeg_names", "L1,L2,L3,L4,R1,R2,R3,R4"}, + {"emg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}, + {"ecg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}, + {"eog_channels", {1, 2, 3, 4, 5, 6, 7, 8}}, + {"rotation_channels", {9, 10, 11}}, + {"battery_channel", 12}, + {"other_channels", {13, 14}} + }; } BrainFlowBoards boards_struct; diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake index 4a4ecd732..0a6632234 100644 --- a/src/board_controller/build.cmake +++ b/src/board_controller/build.cmake @@ -83,6 +83,7 @@ SET (BOARD_CONTROLLER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/brainalive/brainalive.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/emotibit/emotibit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ntl/ntl_wifi.cpp + ${CMAKE_HOME_DIRECTORY}/src/board_controller/aavaa/aavaa_v3.cpp ) include (${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ant_neuro/build.cmake) @@ -138,6 +139,7 @@ target_include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/mentalab/inc ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/emotibit/inc ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ntl/inc + ${CMAKE_HOME_DIRECTORY}/src/board_controller/aavaa/inc ) target_compile_definitions(${BOARD_CONTROLLER_NAME} PRIVATE NOMINMAX BRAINFLOW_VERSION=${BRAINFLOW_VERSION}) diff --git a/src/board_controller/inc/board_info_getter.h b/src/board_controller/inc/board_info_getter.h index 53a423e51..727040d3f 100644 --- a/src/board_controller/inc/board_info_getter.h +++ b/src/board_controller/inc/board_info_getter.h @@ -38,6 +38,8 @@ extern "C" int board_id, int preset, int *eda_channels, int *len); SHARED_EXPORT int CALLING_CONVENTION get_accel_channels ( int board_id, int preset, int *accel_channels, int *len); + SHARED_EXPORT int CALLING_CONVENTION get_rotation_channels ( + int board_id, int preset, int *rotation_channels, int *len); SHARED_EXPORT int CALLING_CONVENTION get_analog_channels ( int board_id, int preset, int *analog_channels, int *len); SHARED_EXPORT int CALLING_CONVENTION get_gyro_channels ( diff --git a/src/utils/inc/brainflow_constants.h b/src/utils/inc/brainflow_constants.h index bc8af72e4..6eb4ce971 100644 --- a/src/utils/inc/brainflow_constants.h +++ b/src/utils/inc/brainflow_constants.h @@ -84,9 +84,10 @@ enum class BoardIds : int NTL_WIFI_BOARD = 50, ANT_NEURO_EE_511_BOARD = 51, FREEEEG128_BOARD = 52, + AAVAA_V3_BOARD = 53, // use it to iterate FIRST = PLAYBACK_FILE_BOARD, - LAST = FREEEEG128_BOARD + LAST = AAVAA_V3_BOARD }; enum class IpProtocolTypes : int diff --git a/third_party/fmt/include/fmt/format-inl.h b/third_party/fmt/include/fmt/format-inl.h index 2c51c50ae..9896be372 100644 --- a/third_party/fmt/include/fmt/format-inl.h +++ b/third_party/fmt/include/fmt/format-inl.h @@ -1696,7 +1696,7 @@ template <> struct cache_accessor { {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, - {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, + {0xf24a01a73cf2dccf, 0xbc633b3967v3cec}, {0x976e41088617ca01, 0xd5be0503e085d813}, {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, diff --git a/tools/build.py b/tools/build.py index fbe7dd46a..b17debf88 100644 --- a/tools/build.py +++ b/tools/build.py @@ -16,7 +16,7 @@ def run_command(cmd, cwd=None): if line: print(line.decode('utf-8', 'ignore'), end='') else: - if p.poll() != None: + if p.poll() is not None: break if p.returncode != 0: raise ValueError('Process finished with error code %d' % p.returncode) @@ -98,7 +98,9 @@ def get_win_generators(): result = list() try: output = subprocess.check_output( - ['C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe', '-property', 'displayName']) + ['C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe', + '-property', + 'displayName']) output = output.decode('utf-8', 'ignore') print(output) if '2022' in output: @@ -135,7 +137,8 @@ def prepare_args(): '--no-oymotion', dest='oymotion', action='store_false') parser.set_defaults(oymotion=False) parser.add_argument('--msvc-runtime', type=str, choices=[ - 'static', 'dynamic'], help='how to link MSVC runtime', required=False, default='static') + 'static', 'dynamic'], + help='how to link MSVC runtime', required=False, default='static') generators = get_win_generators() if not generators: parser.add_argument('--generator', type=str, @@ -150,22 +153,27 @@ def prepare_args(): required=False, default=generator.get_generator()) if generator.get_arch() is not None: parser.add_argument('--arch', type=str, choices=[ - 'x64', 'Win32', 'ARM', 'ARM64'], help='arch for CMake', required=False, default=generator.get_arch()) + 'x64', 'Win32', 'ARM', 'ARM64'], + help='arch for CMake', + required=False, default=generator.get_arch()) else: parser.add_argument('--arch', type=str, choices=[ - 'x64', 'Win32', 'ARM', 'ARM64'], help='arch for CMake', required=False) + 'x64', 'Win32', 'ARM', 'ARM64'], + help='arch for CMake', required=False) if generator.get_sdk_version() is not None: - parser.add_argument('--cmake-system-version', type=str, help='system version for win', + parser.add_argument('--cmake-system-version', type=str, + help='system version for win', required=False, default=generator.get_sdk_version()) else: parser.add_argument( - '--cmake-system-version', type=str, help='system version for win', required=False) + '--cmake-system-version', type=str, + help='system version for win', required=False) elif platform.system() == 'Darwin': macos_ver = platform.mac_ver()[0] versions = [int(x) for x in macos_ver.split('.')] if versions[0] >= 11: parser.add_argument('--cmake-osx-architectures', type=str, - help='archs for osx', required=False, default='"arm64;x86_64"') + help='archs for osx', required=False, default='arm64;x86_64') else: parser.add_argument('--cmake-osx-architectures', type=str, help='archs for osx', required=False) From 82ef5ee58d83a7f08af404ac56f46347ec29b0b9 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Wed, 13 Sep 2023 23:04:42 +0200 Subject: [PATCH 04/16] fix failed ci Signed-off-by: Andrey Parfenov --- src/board_controller/aavaa/aavaa_v3.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/board_controller/aavaa/aavaa_v3.cpp b/src/board_controller/aavaa/aavaa_v3.cpp index 5793e6783..f180c9809 100644 --- a/src/board_controller/aavaa/aavaa_v3.cpp +++ b/src/board_controller/aavaa/aavaa_v3.cpp @@ -506,7 +506,7 @@ void AAVAAv3::read_data ( Incoming_BLE_Data_Buffer.insert (Incoming_BLE_Data_Buffer.end (), data, data + size); } - while (Incoming_BLE_Data_Buffer.size () >= SIZE_OF_DATA_FRAME) + while ((int)Incoming_BLE_Data_Buffer.size () >= SIZE_OF_DATA_FRAME) { if (Incoming_BLE_Data_Buffer[0] != START_BYTE) { @@ -558,8 +558,7 @@ void AAVAAv3::read_data ( package[board_descr["default"]["battery_channel"].get ()] = (double)data_frame[40]; // imu status byte - package[board_descr["default"]["other_channels"][0].get ()] = - (double)data_frame[41]; + package[board_descr["default"]["other_channels"][0].get ()] = (double)data_frame[41]; // timestamp try From 467ee1ec209a1dcc9c7ff5b89dce7984c8d538a5 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Wed, 13 Sep 2023 23:46:29 +0200 Subject: [PATCH 05/16] fixing rust Signed-off-by: Andrey Parfenov --- rust_package/brainflow/src/ffi/board_controller.rs | 9 +-------- rust_package/brainflow/src/ffi/constants.rs | 3 ++- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/rust_package/brainflow/src/ffi/board_controller.rs b/rust_package/brainflow/src/ffi/board_controller.rs index 1a6db0788..eea61650e 100644 --- a/rust_package/brainflow/src/ffi/board_controller.rs +++ b/rust_package/brainflow/src/ffi/board_controller.rs @@ -126,20 +126,13 @@ extern "C" { ) -> ::std::os::raw::c_int; } extern "C" { - pub fn get_rotaiton_channels( + pub fn get_rotation_channels( board_id: ::std::os::raw::c_int, preset: ::std::os::raw::c_int, rotation_channels: *mut ::std::os::raw::c_int, len: *mut ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { - pub fn get_rotaiton_calib_channel( - board_id: ::std::os::raw::c_int, - preset: ::std::os::raw::c_int, - get_rotaiton_calib_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} extern "C" { pub fn get_analog_channels( board_id: ::std::os::raw::c_int, diff --git a/rust_package/brainflow/src/ffi/constants.rs b/rust_package/brainflow/src/ffi/constants.rs index f088b6a1c..216247759 100644 --- a/rust_package/brainflow/src/ffi/constants.rs +++ b/rust_package/brainflow/src/ffi/constants.rs @@ -32,7 +32,7 @@ impl BoardIds { pub const FIRST: BoardIds = BoardIds::PlaybackFileBoard; } impl BoardIds { - pub const LAST: BoardIds = BoardIds::Freeeeg128Board; + pub const LAST: BoardIds = BoardIds::AavaaV3Board; } #[repr(i32)] #[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -91,6 +91,7 @@ pub enum BoardIds { NtlWifiBoard = 50, AntNeuroEe511Board = 51, Freeeeg128Board = 52, + AavaaV3Board = 53, } #[repr(i32)] #[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)] From d71b4cabe8f7bc4c1cda21a5ead404f0c56e00be Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Thu, 14 Sep 2023 01:18:13 +0200 Subject: [PATCH 06/16] Feature/bind js (#665) * add support for nodejs --------- Signed-off-by: Andrey Parfenov Co-authored-by: Gordon Preumont --- .github/workflows/deploy.yml | 30 + .github/workflows/dockerhub.yml | 12 +- .github/workflows/run_unix.yml | 44 + .github/workflows/run_windows.yml | 8 +- Docker/Dockerfile | 17 +- docs/BuildBrainFlow.rst | 17 + docs/Examples.rst | 63 + docs/SupportedBoards.rst | 1 + docs/UserAPI.rst | 10 + docs/requirements.txt | 1 + nodejs_package/.clang-format | 39 + nodejs_package/.eslintrc.json | 21 + nodejs_package/.gitignore | 2 + nodejs_package/.prettierignore | 5 + nodejs_package/.prettierrc | 7 + nodejs_package/LICENSE.txt | 21 + nodejs_package/brainflow/board_shim.ts | 697 ++++ nodejs_package/brainflow/brainflow.types.ts | 260 ++ nodejs_package/brainflow/complex.ts | 245 ++ nodejs_package/brainflow/data_filter.ts | 609 +++ nodejs_package/brainflow/functions.types.ts | 466 +++ nodejs_package/brainflow/index.ts | 5 + nodejs_package/brainflow/ml_model.ts | 205 + nodejs_package/jest.config.js | 6 + nodejs_package/package.json | 54 + nodejs_package/tests/bandpower.ts | 27 + nodejs_package/tests/bandpower_all.ts | 25 + nodejs_package/tests/brainflow_get_data.ts | 21 + nodejs_package/tests/denoising.ts | 25 + nodejs_package/tests/downsampling.ts | 25 + nodejs_package/tests/eeg_metrics.ts | 36 + nodejs_package/tests/ica.ts | 27 + nodejs_package/tests/markers.ts | 23 + nodejs_package/tests/package.json | 29 + nodejs_package/tests/serialization.ts | 26 + nodejs_package/tests/signal_filtering.ts | 32 + nodejs_package/tests/transforms.ts | 39 + nodejs_package/tests/tsconfig.json | 109 + nodejs_package/tsconfig.json | 32 + nodejs_package/yarn.lock | 3643 +++++++++++++++++ src/board_controller/build.cmake | 2 + .../muse/muse_bglib/build.cmake | 2 + .../neuromd/brainbit_bglib/build.cmake | 2 + .../openbci/ganglion_bglib/build.cmake | 2 + src/board_controller/synthetic_board.cpp | 1 + src/data_handler/build.cmake | 2 + src/ml/build.cmake | 2 + src/utils/bluetooth/build.cmake | 2 + .../SimpleBLE/simpleble/CMakeLists.txt | 2 + third_party/gForceSDKCXX/build.cmake | 4 + 50 files changed, 6970 insertions(+), 15 deletions(-) create mode 100644 nodejs_package/.clang-format create mode 100644 nodejs_package/.eslintrc.json create mode 100644 nodejs_package/.gitignore create mode 100644 nodejs_package/.prettierignore create mode 100644 nodejs_package/.prettierrc create mode 100644 nodejs_package/LICENSE.txt create mode 100644 nodejs_package/brainflow/board_shim.ts create mode 100644 nodejs_package/brainflow/brainflow.types.ts create mode 100644 nodejs_package/brainflow/complex.ts create mode 100644 nodejs_package/brainflow/data_filter.ts create mode 100644 nodejs_package/brainflow/functions.types.ts create mode 100644 nodejs_package/brainflow/index.ts create mode 100644 nodejs_package/brainflow/ml_model.ts create mode 100644 nodejs_package/jest.config.js create mode 100644 nodejs_package/package.json create mode 100644 nodejs_package/tests/bandpower.ts create mode 100644 nodejs_package/tests/bandpower_all.ts create mode 100644 nodejs_package/tests/brainflow_get_data.ts create mode 100644 nodejs_package/tests/denoising.ts create mode 100644 nodejs_package/tests/downsampling.ts create mode 100644 nodejs_package/tests/eeg_metrics.ts create mode 100644 nodejs_package/tests/ica.ts create mode 100644 nodejs_package/tests/markers.ts create mode 100644 nodejs_package/tests/package.json create mode 100644 nodejs_package/tests/serialization.ts create mode 100644 nodejs_package/tests/signal_filtering.ts create mode 100644 nodejs_package/tests/transforms.ts create mode 100644 nodejs_package/tests/tsconfig.json create mode 100644 nodejs_package/tsconfig.json create mode 100644 nodejs_package/yarn.lock diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b597720f5..ef4f12a48 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -34,6 +34,14 @@ jobs: python -m pip install twine python -m pip install awscli shell: cmd + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install Typescript + run: | + npm install -g ts-node + shell: cmd - name: Set up JDK 11 uses: actions/setup-java@v1 with: @@ -102,6 +110,24 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Prepare Node Package + run: | + cd $env:GITHUB_WORKSPACE\nodejs_package\ + Copy-Item "$env:GITHUB_WORKSPACE\linux\*" -Destination "$env:GITHUB_WORKSPACE\nodejs_package\brainflow\lib" -Recurse -Force -Filter *.* + Copy-Item "$env:GITHUB_WORKSPACE\macos\*" -Destination "$env:GITHUB_WORKSPACE\nodejs_package\brainflow\lib" -Recurse -Force -Filter *.* + Copy-Item "$env:GITHUB_WORKSPACE\win64\*" -Destination "$env:GITHUB_WORKSPACE\nodejs_package\brainflow\lib" -Recurse -Force -Filter *.* + Copy-Item "$env:GITHUB_WORKSPACE\win32\*" -Destination "$env:GITHUB_WORKSPACE\nodejs_package\brainflow\lib" -Recurse -Force -Filter *.* + ls $env:GITHUB_WORKSPACE\nodejs_package\brainflow\lib + (gc .\package.json).replace('0.0.0-development', $env:VERSION) | Out-File -encoding ASCII package.json + type package.json + npm install + npm run build + npm pack + aws s3 cp $env:GITHUB_WORKSPACE\nodejs_package\ s3://brainflow/$env:GITHUB_SHA/npm --recursive + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + VERSION: ${{ github.event.inputs.version }} - name: Prepare Java Package run: | cd $env:GITHUB_WORKSPACE\java_package\brainflow @@ -196,12 +222,16 @@ jobs: - name: Publish Packages if: github.event.inputs.publish == 'true' run: | + cd $env:GITHUB_WORKSPACE\nodejs_package + echo "//registry.npmjs.org/:_authToken=$env:NPM_TOKEN" > .npmrc + npm publish cd $env:GITHUB_WORKSPACE\java_package\brainflow mvn -s $env:GITHUB_WORKSPACE\java_package\brainflow\settings.xml deploy -Dregistry=https://maven.pkg.github.com/brainflow-dev -Dtoken=$env:PUBLISH_TOKEN cd $env:GITHUB_WORKSPACE\python_package twine upload --skip-existing dist/*.whl --user Andrey1994 --password $env:PYPI_PASSWORD cd $env:GITHUB_WORKSPACE\rust_package\brainflow env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }} PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} PUBLISH_USER: ${{ secrets.PUBLISH_USER }} diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 8f8b0ba05..fd462b9b9 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -4,9 +4,9 @@ on: workflow_dispatch: inputs: version: - description: New Version + description: Git tag to checkout default: "" - required: true + required: false publish: description: Make Public(true or false) default: "false" @@ -26,12 +26,18 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Clone Repository uses: actions/checkout@v2 - - name: Build Docker Container + - name: Build Docker Container with Tag + if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' run: | cd Docker sudo docker build --tag brainflow/brainflow:${VERSION} --build-arg checkout_id=${VERSION} . env: VERSION: ${{ github.event.inputs.version }} + - name: Build Docker Container without Tag + if: github.event_name == 'workflow_dispatch' && github.event.inputs.version == '' + run: | + cd Docker + sudo docker build --tag brainflow/brainflow:0.0.1 . - name: Check Images run: sudo -H docker images - name: DockerHub Login diff --git a/.github/workflows/run_unix.yml b/.github/workflows/run_unix.yml index 4c5ed09ca..3662c8b45 100644 --- a/.github/workflows/run_unix.yml +++ b/.github/workflows/run_unix.yml @@ -33,6 +33,13 @@ jobs: sudo -H apt-get install -y python3-setuptools python3-pygments libbluetooth-dev env: DEBIAN_FRONTEND: noninteractive + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install Typescript + run: | + npm install -g ts-node - name: Install Ninja if: (matrix.os == 'macos-11.0') uses: seanmiddleditch/gha-setup-ninja@master @@ -91,6 +98,15 @@ jobs: run: | cd $GITHUB_WORKSPACE/python_package sudo -H python3 -m pip install -U . + - name: Build Node Package + run: | + cd $GITHUB_WORKSPACE/nodejs_package/brainflow + npm install + npm run build + - name: Install Node Tests + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm install - name: Setup Java package run: | cd $GITHUB_WORKSPACE/java_package/brainflow @@ -305,6 +321,34 @@ jobs: mvn exec:java -Dexec.mainClass="brainflow.examples.EEGMetrics" -Dexec.args="--board-id -1" env: LD_LIBRARY_PATH: ${{ github.workspace }}/installed/lib + - name: Synthetic Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run brainflow_get_data + - name: Signal Filters Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run signal_filtering + - name: Serialization Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run serialization + - name: Downsampling Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run downsampling + - name: Denoising Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run denoising + - name: EEG Metrics Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run eeg_metrics + - name: BandPowerAll Node + run: | + cd $GITHUB_WORKSPACE/nodejs_package/tests + npm run bandpower_all # deploy started - name: Install AWS CLI run: sudo -H python3 -m pip install awscli==1.21.10 diff --git a/.github/workflows/run_windows.yml b/.github/workflows/run_windows.yml index ea405bae8..146c12aa0 100644 --- a/.github/workflows/run_windows.yml +++ b/.github/workflows/run_windows.yml @@ -45,7 +45,7 @@ jobs: run: | mkdir %GITHUB_WORKSPACE%\build32 cd %GITHUB_WORKSPACE%\build32 - cmake -DBRAINFLOW_VERSION=%BRAINFLOW_VERSION% -DBUILD_OYMOTION_SDK=ON -DBUILD_ONNX=ON -DBUILD_BLE=ON -DBUILD_BLUETOOTH=ON -DBUILD_TESTS=ON -DWARNINGS_AS_ERRORS=ON -G "Visual Studio 17 2022" -A Win32 -DCMAKE_SYSTEM_VERSION=8.1 -DCMAKE_INSTALL_PREFIX=..\installed32\ .. + cmake -DBRAINFLOW_VERSION=%BRAINFLOW_VERSION% -DBUILD_OYMOTION_SDK=ON -DBUILD_ONNX=ON -DBUILD_BLE=ON -DBUILD_BLUETOOTH=ON -DWARNINGS_AS_ERRORS=ON -G "Visual Studio 17 2022" -A Win32 -DCMAKE_SYSTEM_VERSION=8.1 -DCMAKE_INSTALL_PREFIX=..\installed32\ .. cmake --build . --target install --config Release -j 2 --parallel 2 env: BRAINFLOW_VERSION: ${{ steps.version.outputs.version }} @@ -54,7 +54,7 @@ jobs: run: | mkdir %GITHUB_WORKSPACE%\build64 cd %GITHUB_WORKSPACE%\build64 - cmake -DBRAINFLOW_VERSION=%BRAINFLOW_VERSION% -DBUILD_OYMOTION_SDK=ON -DBUILD_ONNX=ON -DBUILD_BLE=ON -DBUILD_BLUETOOTH=ON -DBUILD_TESTS=ON -DWARNINGS_AS_ERRORS=ON -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_VERSION=8.1 -DCMAKE_INSTALL_PREFIX=..\installed64\ .. + cmake -DBRAINFLOW_VERSION=%BRAINFLOW_VERSION% -DBUILD_OYMOTION_SDK=ON -DBUILD_ONNX=ON -DBUILD_BLE=ON -DBUILD_BLUETOOTH=ON -DWARNINGS_AS_ERRORS=ON -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_VERSION=8.1 -DCMAKE_INSTALL_PREFIX=..\installed64\ .. cmake --build . --target install --config Release -j 2 --parallel 2 env: BRAINFLOW_VERSION: ${{ steps.version.outputs.version }} @@ -120,10 +120,6 @@ jobs: uses: julia-actions/setup-julia@v1 with: version: 1.3.1 - # Unit testing - - name: Run unit tests - run: .\build\tests\Release\brainflow_tests.exe - shell: cmd # BoardController testing - name: Run Julia Tests run: | diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 281ed638f..bd7ee4c1a 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -13,17 +13,17 @@ echo "deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/" | tee /etc echo "deb https://download.mono-project.com/repo/ubuntu vs-bionic main" | tee /etc/apt/sources.list.d/mono-official-vs.list && \ apt-get -qq update # Installing Dependencies -RUN apt-get install -yqq python3 python3-pip python3-venv openjdk-13-jdk git curl wget build-essential python3-jira r-base rustc cargo nuget nuget mono-devel mono-complete monodevelop libxml2-dev libbluetooth-dev libdbus-1-dev dotnet-sdk-6.0 dotnet-runtime-6.0 dotnet-runtime-3.1 aspnetcore-runtime-6.0 +RUN apt-get install -yqq python3 python3-pip python3-venv openjdk-13-jdk git curl wget build-essential python3-jira r-base rustc cargo nuget nuget mono-devel mono-complete monodevelop libxml2-dev libbluetooth-dev libdbus-1-dev dotnet-sdk-6.0 dotnet-runtime-6.0 dotnet-runtime-3.1 aspnetcore-runtime-6.0 nodejs npm RUN mkdir -p /root/local/bin WORKDIR /root/local/bin # install latest cmake RUN mkdir -p /opt/cmake && wget https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.sh && sh cmake-3.24.3-linux-x86_64.sh --prefix=/opt/cmake --skip-license ENV PATH=/opt/cmake/bin/:$PATH # Installing Maven and Julia -RUN curl "https://miroir.univ-lorraine.fr/apache/maven/maven-3/3.9.4/binaries/apache-maven-3.9.4-bin.tar.gz" -o maven.tar.gz +RUN curl "https://mirrors.estointernet.in/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz" -o maven.tar.gz RUN mkdir -p maven RUN tar xzf maven.tar.gz -C ./maven -RUN export PATH=$PATH:/root/local/bin/maven/apache-maven-3.9.4/bin +RUN export PATH=$PATH:/root/local/bin/maven/apache-maven-3.6.3/bin RUN wget "https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-1.5.3-linux-x86_64.tar.gz" RUN mkdir -p julia RUN tar xf julia-1.5.3-linux-x86_64.tar.gz -C ./julia @@ -33,11 +33,11 @@ ENV PATH=$PATH:/root/local/bin/julia/julia-1.5.3/bin RUN python3 -m pip install scipy pandas matplotlib mne jupyterlab notebook opencv-python pyriemann WORKDIR /root -ARG checkout_id +ARG checkout_id="none" # Compile RUN git clone "https://github.com/brainflow-dev/brainflow.git" WORKDIR /root/brainflow -RUN if [ ! -z "${checkout_id}" ]; then git checkout "${checkout_id}"; fi +RUN if [ "${checkout_id}" != "none" ]; then git checkout "${checkout_id}"; fi RUN python3 ./tools/build.py --use-openmp --bluetooth --ble ENV LD_LIBRARY_PATH=/root/brainflow/installed_linux/lib/ @@ -54,7 +54,7 @@ RUN dotnet build csharp_package/brainflow/brainflow.sln # Java Binding WORKDIR /root/brainflow/java_package/brainflow -RUN /root/local/bin/maven/apache-maven-3.9.4/bin/mvn package +RUN /root/local/bin/maven/apache-maven-3.6.3/bin/mvn package # Julia Bindings WORKDIR /root/brainflow/julia_package/brainflow @@ -67,6 +67,11 @@ RUN R --vanilla -e 'install.packages("knitr", repos="http://cran.us.r-project.or RUN R --vanilla -e 'install.packages("reticulate", repos="http://cran.us.r-project.org")' RUN R CMD build . +# Node JS Binding +WORKDIR /root/brainflow/nodejs_binding/brainflow +RUN npm install -g ts-node +RUN npm install + # Rust Binding WORKDIR /root/brainflow/rust_package/brainflow RUN cargo build diff --git a/docs/BuildBrainFlow.rst b/docs/BuildBrainFlow.rst index 4143c206a..578cbc924 100644 --- a/docs/BuildBrainFlow.rst +++ b/docs/BuildBrainFlow.rst @@ -121,6 +121,23 @@ When using BrainFlow for the first time in Julia, the BrainFlow artifact contain If you compile BrainFlow from source local libraries will take precedence over the artifact. +Typescript +----------- + +.. compound:: + + You can install BrainFlow using next command without compilation :: + + npm install brainflow + +.. compound:: + + If you want to install it from source files or build unreleased version from Github, you should first compile the core module (:ref:`compilation-label`). Then run :: + + cd nodejs_package + npm install --force + + Rust ------- diff --git a/docs/Examples.rst b/docs/Examples.rst index 7b354c9f7..eae4c7e7d 100644 --- a/docs/Examples.rst +++ b/docs/Examples.rst @@ -539,6 +539,69 @@ Rust ICA .. literalinclude:: ../rust_package/brainflow/examples/ica.rs :language: rust +Typescript +------------ + +Typescript Get Data from a Board +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/brainflow_get_data.ts + :language: javascript + +Typescript Markers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/markers.ts + :language: javascript + +Typescript Read Write File +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/serialization.ts + :language: javascript + +Typescript Downsample Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/downsampling.ts + :language: javascript + +Typescript Transforms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/transforms.ts + :language: javascript + +Typescript Signal Filtering +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/signal_filtering.ts + :language: javascript + +Typescript Denoising +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/denoising.ts + :language: javascript + +Typescript Band Power +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/bandpower.ts + :language: javascript + +Typescript EEG Metrics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/eeg_metrics.ts + :language: javascript + +Typescript ICA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../nodejs_package/tests/ica.ts + :language: javascript + Notebooks ------------ .. toctree:: diff --git a/docs/SupportedBoards.rst b/docs/SupportedBoards.rst index 0c574fa49..f1dfb13b2 100644 --- a/docs/SupportedBoards.rst +++ b/docs/SupportedBoards.rst @@ -730,6 +730,7 @@ To create such board you need to specify the following board ID and fields of Br Initialization Example: .. code-block:: python + params = BrainFlowInputParams() params.serial_port = "COM6" board = BoardShim(BoardIds.FREEEEG128_BOARD, params) diff --git a/docs/UserAPI.rst b/docs/UserAPI.rst index e54bf4357..3eb6fec9f 100644 --- a/docs/UserAPI.rst +++ b/docs/UserAPI.rst @@ -159,3 +159,13 @@ Example: .. literalinclude:: ../rust_package/brainflow/examples/get_data.rs :language: rust + +Typescript API Reference +-------------------------- + +Typescript binding calls C/C++ code as any other binding. Use Typescript examples and API reference for other languaes as a starting point. + +Example: + +.. literalinclude:: ../nodejs_package/tests/brainflow_get_data.ts + :language: javascript diff --git a/docs/requirements.txt b/docs/requirements.txt index 438d93ad4..f95adda1a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -12,3 +12,4 @@ Pygments==2.7.4 sphinxcontrib-matlabdomain==0.11.4 docutils<0.17 sphinx_rtd_theme==0.4.3 +jinja2<3.1 \ No newline at end of file diff --git a/nodejs_package/.clang-format b/nodejs_package/.clang-format new file mode 100644 index 000000000..3ec778bdd --- /dev/null +++ b/nodejs_package/.clang-format @@ -0,0 +1,39 @@ +--- +BasedOnStyle: WebKit +AccessModifierOffset: '-4' +AlignEscapedNewlinesLeft: 'false' +AlignTrailingComments: 'true' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'true' +BinPackParameters: 'true' +BreakBeforeBinaryOperators: 'false' +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: 'false' +BreakConstructorInitializersBeforeComma: 'false' +ColumnLimit: '100' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' +DisableFormat: 'false' +IndentCaseLabels: 'true' +IndentWidth: '4' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +Language: JavaScript +MaxEmptyLinesToKeep: '2' +NamespaceIndentation: All +PointerAlignment: Right +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeParens: Always +SpaceInEmptyParentheses: 'false' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +Standard: Cpp11 +TabWidth: '4' +UseTab: Never + +... diff --git a/nodejs_package/.eslintrc.json b/nodejs_package/.eslintrc.json new file mode 100644 index 000000000..630e4bc8a --- /dev/null +++ b/nodejs_package/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "env": { "es6": true, "node": true }, + "extends": [ + "eslint:recommended", + "prettier", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint", "prettier"], + "rules": { + "prettier/prettier": ["error"], + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/explicit-function-return-type": 0 + } +} diff --git a/nodejs_package/.gitignore b/nodejs_package/.gitignore new file mode 100644 index 000000000..9b26ed04f --- /dev/null +++ b/nodejs_package/.gitignore @@ -0,0 +1,2 @@ +node_modules +lib \ No newline at end of file diff --git a/nodejs_package/.prettierignore b/nodejs_package/.prettierignore new file mode 100644 index 000000000..79dc4c1c9 --- /dev/null +++ b/nodejs_package/.prettierignore @@ -0,0 +1,5 @@ +# Add files here to ignore them from prettier formatting + +/dist +/tmp + diff --git a/nodejs_package/.prettierrc b/nodejs_package/.prettierrc new file mode 100644 index 000000000..17397e3ff --- /dev/null +++ b/nodejs_package/.prettierrc @@ -0,0 +1,7 @@ +{ + "arrowParens": "always", + "singleQuote": true, + "semi": true, + "trailingComma": "all", + "printWidth": 120 +} diff --git a/nodejs_package/LICENSE.txt b/nodejs_package/LICENSE.txt new file mode 100644 index 000000000..6a1b5f8c9 --- /dev/null +++ b/nodejs_package/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Andrey Parfenov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/nodejs_package/brainflow/board_shim.ts b/nodejs_package/brainflow/board_shim.ts new file mode 100644 index 000000000..309e9f2ad --- /dev/null +++ b/nodejs_package/brainflow/board_shim.ts @@ -0,0 +1,697 @@ +import koffi from 'koffi'; +import _ from 'lodash'; +import * as os from 'os'; + +import { + BoardIds, + BrainFlowError, + BrainFlowExitCodes, + BrainFlowPresets, + IBrainFlowInputParams, + IpProtocolTypes, + LogLevels, +} from './brainflow.types'; +import {BoardControllerCLikeFunctions as CLike, BoardControllerFunctions} from './functions.types'; + +export class BrainFlowInputParams +{ + private inputParams: IBrainFlowInputParams = { + serialPort: '', + macAddress: '', + ipAddress: '', + ipAddressAux: '', + ipAddressAnc: '', + ipPort: 0, + ipPortAux: 0, + ipPortAnc: 0, + ipProtocol: IpProtocolTypes.NO_IP_PROTOCOL, + otherInfo: '', + timeout: 0, + serialNumber: '', + file: '', + fileAux: '', + fileAnc: '', + masterBoard: BoardIds.NO_BOARD, + }; + + constructor(inputParams: Partial) + { + this.inputParams = {...this.inputParams, ...inputParams }; + } + + public toJson(): string + { + const params: Record = {}; + Object.keys(this.inputParams).forEach((key) => { + params[_.snakeCase(key)] = this.inputParams[key as keyof IBrainFlowInputParams]; + }); + return JSON.stringify(params); + } +} + +class BoardControllerDLL extends BoardControllerFunctions +{ + private static instance: BoardControllerDLL; + + private libPath: string; + private dllPath: string; + private lib: koffi.IKoffiLib; + + private constructor() + { + super (); + this.libPath = `${__dirname}/../brainflow/lib`; + this.dllPath = this.getDLLPath(); + this.lib = this.getLib(); + + this.isPrepared = this.lib.func(CLike.is_prepared); + this.prepareSession = this.lib.func(CLike.prepare_session); + this.startStream = this.lib.func(CLike.start_stream); + this.configBoard = this.lib.func(CLike.config_board); + this.getBoardDataCount = this.lib.func(CLike.get_board_data_count); + this.getBoardData = this.lib.func(CLike.get_board_data); + this.getCurrentBoardData = this.lib.func(CLike.get_current_board_data); + this.getNumRows = this.lib.func(CLike.get_num_rows); + this.releaseAllSessions = this.lib.func(CLike.release_all_sessions); + this.releaseSession = this.lib.func(CLike.release_session); + this.stopStream = this.lib.func(CLike.stop_stream); + this.getSamplingRate = this.lib.func(CLike.get_sampling_rate); + this.getPackageNumChannel = this.lib.func(CLike.get_package_num_channel); + this.getTimestampChannel = this.lib.func(CLike.get_timestamp_channel); + this.getMarkerChannel = this.lib.func(CLike.get_marker_channel); + this.getBatteryChannel = this.lib.func(CLike.get_battery_channel); + this.getEegChannels = this.lib.func(CLike.get_eeg_channels); + this.getExgChannels = this.lib.func(CLike.get_exg_channels); + this.getEmgChannels = this.lib.func(CLike.get_emg_channels); + this.getEogChannels = this.lib.func(CLike.get_eog_channels); + this.getEcgChannels = this.lib.func(CLike.get_ecg_channels); + this.getPpgChannels = this.lib.func(CLike.get_ppg_channels); + this.getEdaChannels = this.lib.func(CLike.get_eda_channels); + this.getAccelChannels = this.lib.func(CLike.get_accel_channels); + this.getRotationChannels = this.lib.func(CLike.get_rotation_channels); + this.getAnalogChannels = this.lib.func(CLike.get_analog_channels); + this.getGyroChannels = this.lib.func(CLike.get_gyro_channels); + this.getOtherChannels = this.lib.func(CLike.get_other_channels); + this.getTemperatureChannels = this.lib.func(CLike.get_temperature_channels); + this.getResistanceChannels = this.lib.func(CLike.get_resistance_channels); + this.getMagnetometerChannels = this.lib.func(CLike.get_magnetometer_channels); + this.addStreamer = this.lib.func(CLike.add_streamer); + this.deleteStreamer = this.lib.func(CLike.delete_streamer); + this.insertMarker = this.lib.func(CLike.insert_marker); + this.setLogLevelBoardController = this.lib.func(CLike.set_log_level_board_controller); + this.setLogFileBoardController = this.lib.func(CLike.set_log_file_board_controller); + this.logMessageBoardController = this.lib.func(CLike.log_message_board_controller); + this.getVersionBoardController = this.lib.func(CLike.get_version_board_controller); + this.getDeviceName = this.lib.func(CLike.get_device_name); + this.getBoardPresets = this.lib.func(CLike.get_board_presets); + this.getEegNames = this.lib.func(CLike.get_eeg_names); + this.getBoardDescr = this.lib.func(CLike.get_board_descr); + } + + private getDLLPath() + { + const platform = os.platform(); + const arch = os.arch(); + switch (platform) + { + case 'darwin': + return `${this.libPath}/libBoardController.dylib`; + case 'win32': + return arch === 'x64' ? `${this.libPath}/BoardController.dll` : + `${this.libPath}/BoardController32.dll`; + case 'linux': + return `${this.libPath}/libBoardController.so`; + default: + throw new BrainFlowError ( + BrainFlowExitCodes.GENERAL_ERROR, `OS ${platform} is not supported.`); + } + } + + private getLib() + { + try + { + const lib = koffi.load(this.dllPath); + return lib; + } + catch (err) + { + console.error(err); + throw new BrainFlowError (BrainFlowExitCodes.GENERAL_ERROR, + `${'Could not load BoardController DLL - path://'}${this.dllPath}`); + } + } + + public static getInstance(): BoardControllerDLL + { + if (!BoardControllerDLL.instance) + { + BoardControllerDLL.instance = new BoardControllerDLL (); + } + return BoardControllerDLL.instance; + } +} + +export class BoardShim +{ + private boardId: BoardIds; + + private masterBoardId: BoardIds; + + private inputJson: string; + + constructor(boardId: BoardIds, inputParams: Partial) + { + this.boardId = boardId; + this.masterBoardId = + inputParams.masterBoard && inputParams.masterBoard !== BoardIds.NO_BOARD ? + inputParams.masterBoard : + boardId; + this.inputJson = new BrainFlowInputParams (inputParams).toJson(); + } + + // logging methods + public static getVersion(): string + { + const len = [0]; + let out = ['\0'.repeat(512)]; + const res = BoardControllerDLL.getInstance().getVersionBoardController(out, len, 512); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get version info'); + } + return out[0].substring(0, len[0]); + } + + public static setLogLevel(logLevel: LogLevels): void + { + const res = BoardControllerDLL.getInstance().setLogLevelBoardController(logLevel); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not set log level properly'); + } + } + + public static setLogFile(file: string): void + { + const res = BoardControllerDLL.getInstance().setLogFileBoardController(file); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not redirect to log file'); + } + } + + public static logMessage(logLevel: LogLevels, message: string): void + { + const res = BoardControllerDLL.getInstance().logMessageBoardController(logLevel, message); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not writte message'); + } + } + + // board methods + public prepareSession(): void + { + const res = BoardControllerDLL.getInstance().prepareSession(this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not prepare session'); + } + } + + public isPrepared(): boolean + { + const prepared = [0]; + const res = + BoardControllerDLL.getInstance().isPrepared(prepared, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not check prepared state'); + } + return !!prepared[0]; + } + + public addStreamer(streamerParams: string, preset = BrainFlowPresets.DEFAULT_PRESET): void + { + const res = BoardControllerDLL.getInstance().addStreamer( + streamerParams, preset, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not add streamer'); + } + } + + public deleteStreamer(streamerParams: string, preset = BrainFlowPresets.DEFAULT_PRESET): void + { + const res = BoardControllerDLL.getInstance().deleteStreamer( + streamerParams, preset, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not delete streamer'); + } + } + + public insertMarker(value: number, preset = BrainFlowPresets.DEFAULT_PRESET): void + { + const res = BoardControllerDLL.getInstance().insertMarker( + value, preset, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not insert marker'); + } + } + + public startStream(numSamples = 1800 * 250, streamerParams = null): void + { + const res = BoardControllerDLL.getInstance().startStream( + numSamples, streamerParams, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not start stream'); + } + } + + public configBoard(config: string): string + { + const len = [0]; + let out = ['\0'.repeat(4096)]; + const res = BoardControllerDLL.getInstance().configBoard( + config, out, len, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not config board'); + } + return out[0].substring(0, len[0]); + } + + public getBoardDataCount(preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const dataSize = [0]; + const res = BoardControllerDLL.getInstance().getBoardDataCount( + preset, dataSize, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board data count'); + } + return dataSize[0]; + } + + public getBoardData(numSamples?: number, preset = BrainFlowPresets.DEFAULT_PRESET): number[][] + { + let dataSize = this.getBoardDataCount(preset); + if (numSamples) + { + if (numSamples < 1) + throw new Error ('invalid num_samples'); + dataSize = Math.min(numSamples, dataSize); + } + const packageLength = BoardShim.getNumRows(this.masterBoardId, preset); + const dataArr = [...new Array (packageLength * dataSize).fill(0)]; + const res = BoardControllerDLL.getInstance().getBoardData( + dataSize, preset, dataArr, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board data'); + } + return _.chunk(dataArr, dataSize); + } + + public getCurrentBoardData( + numSamples: number, preset = BrainFlowPresets.DEFAULT_PRESET): number[][] + { + const packageLength = BoardShim.getNumRows(this.masterBoardId, preset); + const dataArr = [...new Array (packageLength * numSamples).fill(0)]; + const currentSize = [0]; + const res = BoardControllerDLL.getInstance().getCurrentBoardData( + numSamples, + preset, + dataArr, + currentSize, + this.boardId, + this.inputJson, + ); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get current board data'); + } + return _.chunk(dataArr, currentSize[0]); + } + + public stopStream(): void + { + const res = BoardControllerDLL.getInstance().stopStream(this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not stop stream'); + } + } + + public releaseSession(): void + { + const res = BoardControllerDLL.getInstance().releaseSession(this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not release session'); + } + } + + public static releaseAllSessions(): void + { + const res = BoardControllerDLL.getInstance().releaseAllSessions(); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not release all sessions'); + } + } + + // board info getter methods + public static getNumRows(boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const numRows = [0]; + const res = BoardControllerDLL.getInstance().getNumRows(boardId, preset, numRows); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get num rows'); + } + return numRows[0]; + } + + public static getPackageNumChannel( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const value = [0]; + const res = BoardControllerDLL.getInstance().getPackageNumChannel(boardId, preset, value); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get such data from this device'); + } + return value[0]; + } + + public static getTimestampChannel( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const value = [0]; + const res = BoardControllerDLL.getInstance().getTimestampChannel(boardId, preset, value); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get such data from this device'); + } + return value[0]; + } + + public static getMarkerChannel( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const value = [0]; + const res = BoardControllerDLL.getInstance().getMarkerChannel(boardId, preset, value); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get such data from this device'); + } + return value[0]; + } + + public static getBatteryChannel( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const value = [0]; + const res = BoardControllerDLL.getInstance().getBatteryChannel(boardId, preset, value); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get such data from this device'); + } + return value[0]; + } + + public static getSamplingRate( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number + { + const samplingRate = [0]; + const res = BoardControllerDLL.getInstance().getSamplingRate(boardId, preset, samplingRate); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get sampling rate'); + } + return samplingRate[0]; + } + + public static getEegChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const eegChannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getEegChannels( + boardId, preset, eegChannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return eegChannels.slice(0, numChannels[0]); + } + + public static getExgChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getExgChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getEmgChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getEmgChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getEcgChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getEcgChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getEogChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getEogChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getPpgChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getPpgChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getEdaChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = + BoardControllerDLL.getInstance().getEdaChannels(boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getAccelChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getAccelChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getRotationChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getRotationChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getAnalogChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getAnalogChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getGyroChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getGyroChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getOtherChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getOtherChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getTemperatureChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getTemperatureChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getResistanceChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getResistanceChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getMagnetometerChannels( + boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): number[] + { + const numChannels = [0]; + const сhannels = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getMagnetometerChannels( + boardId, preset, сhannels, numChannels); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return сhannels.slice(0, numChannels[0]); + } + + public static getBoardPresets(boardId: BoardIds): number[] + { + const len = [0]; + const presets = [...new Array (512).fill(0)]; + const res = BoardControllerDLL.getInstance().getBoardPresets(boardId, presets, len); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get board info'); + } + return presets.slice(0, len[0]); + } + + public static getDeviceName(boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): string + { + const len = [0]; + let out = ['\0'.repeat(512)]; + const res = BoardControllerDLL.getInstance().getDeviceName(boardId, preset, out, len); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get device info'); + } + return out[0].substring(0, len[0]); + } + + public static getEegNames(boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): string[] + { + const len = [0]; + let out = ['\0'.repeat(4096)]; + const res = BoardControllerDLL.getInstance().getEegNames(boardId, preset, out, len); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get device info'); + } + return out[0].substring(0, len[0]).split(","); + } + + public static getBoardDescr(boardId: BoardIds, preset = BrainFlowPresets.DEFAULT_PRESET): Object + { + const len = [0]; + let out = ['\0'.repeat(4096)]; + const res = BoardControllerDLL.getInstance().getBoardDescr(boardId, preset, out, len); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get device info'); + } + return JSON.parse(out[0].substring(0, len[0])); + } +} \ No newline at end of file diff --git a/nodejs_package/brainflow/brainflow.types.ts b/nodejs_package/brainflow/brainflow.types.ts new file mode 100644 index 000000000..15e3a9150 --- /dev/null +++ b/nodejs_package/brainflow/brainflow.types.ts @@ -0,0 +1,260 @@ +export class BrainFlowError extends Error +{ + __proto__ = Error + + public exitCode: number; + + constructor(errorCode: number, msg: string) + { + super ("Error code is: " + errorCode + " " + msg); + this.exitCode = errorCode; + Object.setPrototypeOf(this, BrainFlowError.prototype); + } +} + +export enum BoardIds { + NO_BOARD = -100, + PLAYBACK_FILE_BOARD = -3, + STREAMING_BOARD = -2, + SYNTHETIC_BOARD = -1, + CYTON_BOARD = 0, + GANGLION_BOARD = 1, + CYTON_DAISY_BOARD = 2, + GALEA_BOARD = 3, + GANGLION_WIFI_BOARD = 4, + CYTON_WIFI_BOARD = 5, + CYTON_DAISY_WIFI_BOARD = 6, + BRAINBIT_BOARD = 7, + UNICORN_BOARD = 8, + CALLIBRI_EEG_BOARD = 9, + CALLIBRI_EMG_BOARD = 10, + CALLIBRI_ECG_BOARD = 11, + NOTION_1_BOARD = 13, + NOTION_2_BOARD = 14, + GFORCE_PRO_BOARD = 16, + FREEEEG32_BOARD = 17, + BRAINBIT_BLED_BOARD = 18, + GFORCE_DUAL_BOARD = 19, + GALEA_SERIAL_BOARD = 20, + MUSE_S_BLED_BOARD = 21, + MUSE_2_BLED_BOARD = 22, + CROWN_BOARD = 23, + ANT_NEURO_EE_410_BOARD = 24, + ANT_NEURO_EE_411_BOARD = 25, + ANT_NEURO_EE_430_BOARD = 26, + ANT_NEURO_EE_211_BOARD = 27, + ANT_NEURO_EE_212_BOARD = 28, + ANT_NEURO_EE_213_BOARD = 29, + ANT_NEURO_EE_214_BOARD = 30, + ANT_NEURO_EE_215_BOARD = 31, + ANT_NEURO_EE_221_BOARD = 32, + ANT_NEURO_EE_222_BOARD = 33, + ANT_NEURO_EE_223_BOARD = 34, + ANT_NEURO_EE_224_BOARD = 35, + ANT_NEURO_EE_225_BOARD = 36, + ENOPHONE_BOARD = 37, + MUSE_2_BOARD = 38, + MUSE_S_BOARD = 39, + BRAINALIVE_BOARD = 40, + MUSE_2016_BOARD = 41, + MUSE_2016_BLED_BOARD = 42, + EXPLORE_4_CHAN_BOARD = 44, + EXPLORE_8_CHAN_BOARD = 45, + GANGLION_NATIVE_BOARD = 46, + EMOTIBIT_BOARD = 47, + GALEA_BOARD_V4 = 48, + GALEA_SERIAL_BOARD_V4 = 49, + NTL_WIFI_BOARD = 50, + ANT_NEURO_EE_511_BOARD = 51, +} + +export enum IpProtocolTypes { + NO_IP_PROTOCOL = 0, + UDP = 1, + TCP = 2, +} + +export enum BrainFlowPresets { + DEFAULT_PRESET = 0, + AUXILIARY_PRESET = 1, + ANCILLARY_PRESET = 2, +} + +export enum LogLevels { + LEVEL_TRACE = 0, + LEVEL_DEBUG = 1, + LEVEL_INFO = 2, + LEVEL_WARN = 3, + LEVEL_ERROR = 4, + LEVEL_CRITICAL = 5, + LEVEL_OFF = 6, +} + +export enum FilterTypes { + BUTTERWORTH = 0, + CHEBYSHEV_TYPE_1 = 1, + BESSEL = 2, + BUTTERWORTH_ZERO_PHASE = 3, + CHEBYSHEV_TYPE_1_ZERO_PHASE = 4, + BESSEL_ZERO_PHASE = 5, +} + +export enum AggOperations { + MEAN = 0, + MEDIAN = 1, + EACH = 2, +} + +export enum WindowOperations { + NO_WINDOW = 0, + HANNING = 1, + HAMMING = 2, + BLACKMAN_HARRIS = 3, +} + +export enum DetrendOperations { + NO_DETREND = 0, + CONSTANT = 1, + LINEAR = 2, +} + +export enum NoiseTypes { + FIFTY = 0, + SIXTY = 1, + FIFTY_AND_SIXTY = 2, +} + +export enum WaveletDenoisingTypes { + VISUSHRINK = 0, + SURESHRINK = 1, +} + +export enum ThresholdTypes { + SOFT = 0, + HARD = 1, +} + +export enum WaveletExtensionTypes { + SYMMETRIC = 0, + PERIODIC = 1, +} + +export enum NoiseEstimationLevelTypes { + FIRST_LEVEL = 0, + ALL_LEVELS = 1, +} + +export enum WaveletTypes { + HAAR = 0, + DB1 = 1, + DB2 = 2, + DB3 = 3, + DB4 = 4, + DB5 = 5, + DB6 = 6, + DB7 = 7, + DB8 = 8, + DB9 = 9, + DB10 = 10, + DB11 = 11, + DB12 = 12, + DB13 = 13, + DB14 = 14, + DB15 = 15, + BIOR1_1 = 16, + BIOR1_3 = 17, + BIOR1_5 = 18, + BIOR2_2 = 19, + BIOR2_4 = 20, + BIOR2_6 = 21, + BIOR2_8 = 22, + BIOR3_1 = 23, + BIOR3_3 = 24, + BIOR3_5 = 25, + BIOR3_7 = 26, + BIOR3_9 = 27, + BIOR4_4 = 28, + BIOR5_5 = 29, + BIOR6_8 = 30, + COIF1 = 31, + COIF2 = 32, + COIF3 = 33, + COIF4 = 34, + COIF5 = 35, + SYM2 = 36, + SYM3 = 37, + SYM4 = 38, + SYM5 = 39, + SYM6 = 40, + SYM7 = 41, + SYM8 = 42, + SYM9 = 43, + SYM10 = 44, +} + +export enum BrainFlowExitCodes { + STATUS_OK = 0, + PORT_ALREADY_OPEN_ERROR = 1, + UNABLE_TO_OPEN_PORT_ERROR = 2, + SER_PORT_ERROR = 3, + BOARD_WRITE_ERROR = 4, + INCOMMING_MSG_ERROR = 5, + INITIAL_MSG_ERROR = 6, + BOARD_NOT_READY_ERROR = 7, + STREAM_ALREADY_RUN_ERROR = 8, + INVALID_BUFFER_SIZE_ERROR = 9, + STREAM_THREAD_ERROR = 10, + STREAM_THREAD_IS_NOT_RUNNING = 11, + EMPTY_BUFFER_ERROR = 12, + INVALID_ARGUMENTS_ERROR = 13, + UNSUPPORTED_BOARD_ERROR = 14, + BOARD_NOT_CREATED_ERROR = 15, + ANOTHER_BOARD_IS_CREATED_ERROR = 16, + GENERAL_ERROR = 17, + SYNC_TIMEOUT_ERROR = 18, + JSON_NOT_FOUND_ERROR = 19, + NO_SUCH_DATA_IN_JSON_ERROR = 20, + CLASSIFIER_IS_NOT_PREPARED_ERROR = 21, + ANOTHER_CLASSIFIER_IS_PREPARED_ERROR = 22, + UNSUPPORTED_CLASSIFIER_AND_METRIC_COMBINATION_ERROR = 23, +} + +export enum BrainFlowMetrics { + MINDFULNESS = 0, + RESTFULNESS = 1, + USER_DEFINED = 2, +} + +export enum BrainFlowClassifiers { + DEFAULT_CLASSIFIER = 0, + USER_DEFINED = 1, + ONNX_CLASSIFIER = 2, +} + +export interface IBrainFlowInputParams { + serialPort: string; + macAddress: string; + ipAddress: string; + ipAddressAux: string; + ipAddressAnc: string; + ipPort: number; + ipPortAux: number; + ipPortAnc: number; + ipProtocol: IpProtocolTypes; + otherInfo: string; + timeout: number; + serialNumber: string; + file: string; + fileAux: string; + fileAnc: string; + masterBoard: BoardIds; +} + +export interface IBrainFlowModelParams { + metric: BrainFlowMetrics; + classifier: BrainFlowClassifiers; + file: string; + otherInfo: string; + outputName: string; + maxArraySize: number; +} diff --git a/nodejs_package/brainflow/complex.ts b/nodejs_package/brainflow/complex.ts new file mode 100644 index 000000000..833311dac --- /dev/null +++ b/nodejs_package/brainflow/complex.ts @@ -0,0 +1,245 @@ +export class complex +{ + /** The real component of the complex number */ + private _real: number; + /** The imaginary component of the complex number */ + private _img: number; + + /** + * Construct a new complex number from two real numbers + * @param real - The real component + * @param imaginary - The imaginary component + * @returns Complex number constructed from given parameters + */ + constructor(real: number, imaginary: number) + { + this._real = real; + this._img = imaginary; + } + + /** + * Get the real component of the complex number + * @returns The real component - this._real + */ + get real(): number + { + return this._real; + } + + /** + * Get the imaginary component of the complex number + * @returns The imaginary component - this._imaginary + */ + get img(): number + { + return this._img; + } + + /** + * Add two complex numbers + * @param other - The 2nd complex number operand + * @returns x + other + */ + public add(other: complex): complex + { + return new complex (this._real + other.real, this._img + other.img); + } + + /** + * Subtract two complex numbers + * @param other - The 2nd complex number operand + * @returns x - other + */ + public sub(other: complex): complex + { + return new complex (this._real - other.real, this._img - other.img); + } + + /** + * Multiply two complex numbers + * @param other - The 2nd complex number operand + * @returns The product of x / other + */ + public mult(other: complex): complex + { + return new complex (this.real * other.real - this._img * other.img, + this.real * other.img + this._img * other.real); + } + + /** + * Divide two complex numbers + * @param other - The 2nd complex number operand + * @returns The result of the division x / other + */ + public div(other: complex): complex + { + /* Complex division: + ac + bd bc - ad + -------- + -------- i + c^2 + d^2 c^2 + d^2 + */ + let ac = this._real * other.real; + let bd = this._img * other.img; + let bc = this._img * other.real; + let ad = this._real * other.img; + let cc = other.real * other.real; + let dd = other.img * other.img; + return new complex ((ac + bd) / (cc + dd), (bc - ad) / (cc + dd)); + } + + /** + * Scalar multiply a complex number, by a real number lambda + * @param lambda - The real number scaling factor + * @returns The scaled version of the complex number + */ + public scalarMult(lambda: number): complex + { + return new complex (lambda * this.real, lambda * this.img); + } + + /** + * Get the magnitude(absolute value) of the complex number + * @returns The magnitude: sqroot(a^2 + b^2) + */ + public mag(): number + { + return Math.sqrt((this.real * this.real) + (this.img * this.img)); + } + + /** + * Get the conjugate of the complex number + * @returns The conjugate of the complex number: a + (-bi) + */ + public conj(): complex + { + return new complex (this.real, -this.img); + } + + /** + * Get the negation of the complex number + * @returns The negation of the complex number: -a + (-bi) + */ + public neg(): complex + { + return new complex (-this.real, -this.img); + } + + /** + * Get the arguement of the complex number, the angle in radians with the x-axis in polar + * coordinates + * @returns The arguement of the complex number + */ + public arg(): number + { + return Math.atan2(this.img, this.real); + } + + /** + * Get the exponential of the complex number + * @returns The exponential of the complex number: (exp(a) * cos(b)) + (exp(a) * sin(b))(i) + */ + public exp(): complex + { + return new complex ( + Math.exp(this.real) * Math.cos(this.img), Math.exp(this.real) * Math.sin(this.img)); + } + + /** + * Get the natural base e log of the complex number + * @returns The natural base e log of the complex number + */ + public log(): complex + { + return new complex (Math.log(this.mag()), Math.atan2(this.img, this.real)); + } + + /** + * Get the sine of the complex number + * @returns The sine of the complex number + */ + public sin(): complex + { + return new complex ( + Math.cosh(this.img) * Math.sin(this.real), Math.sinh(this.img) * Math.cos(this.real)); + } + + /** + * Get the cosine of the complex number + * @returns The cosine of the complex number + */ + public cos(): complex + { + return new complex ( + Math.cosh(this.img) * Math.cos(this.real), -Math.sinh(this.img) * Math.sin(this.real)); + } + + /** + * Get the tangent of the complex number + * @returns The tangent of the complex number + */ + public tan(): complex + { + // defined in terms of the identity tan(z) = sin(z) / cos(z) + let num = this.sin(); + let denom = this.cos(); + return num.div(denom); + } + + /** + * Static method to construct a complex number in rectangular form from polar coordinates + * @param theta - The angle/arguement + * @param magnitude - The magnitude + * @returns Complex number in rectangular coordinates constructed from the arguement theta & the + * magnitude + */ + public static fromPolar(theta: number, magnitude: number): complex + { + return new complex (magnitude * Math.cos(theta), magnitude * Math.sin(theta)); + } + + /** + * Get the complex number's polar coordinates as a tuple + * @returns A tuple containing the arguement/angle of the complex number as the 1st element, and + * the magnitude as the 2nd + */ + public toPolar(): [number, number] + { + let mag = this.mag(); + let theta = this.arg(); + return [theta, mag]; + } + + /** + * Get the complex number as a string + * @returns String representation of the complex number + */ + public toString(): string + { + if (Math.sign(this.img) === -1) + { + // bit of a dirty hack.. + return this.real + " - " + -this.img + "i"; + } + else + { + return this.real + " + " + this.img + "i"; + } + } + + /** + * Compare two complex numbers for equality + * @param other - The 2nd complex number operand + * @returns true if equal, else false + */ + public equals(other: complex): boolean + { + if (this.real === other.real && this.img === other.img) + { + return true; + } + else + { + return false; + } + } +} \ No newline at end of file diff --git a/nodejs_package/brainflow/data_filter.ts b/nodejs_package/brainflow/data_filter.ts new file mode 100644 index 000000000..8ae4fa43d --- /dev/null +++ b/nodejs_package/brainflow/data_filter.ts @@ -0,0 +1,609 @@ +import koffi from 'koffi'; +import _ from 'lodash'; +import os from 'os'; + +import { + AggOperations, + BrainFlowError, + BrainFlowExitCodes, + DetrendOperations, + FilterTypes, + LogLevels, + NoiseEstimationLevelTypes, + NoiseTypes, + ThresholdTypes, + WaveletDenoisingTypes, + WaveletExtensionTypes, + WaveletTypes, + WindowOperations +} from './brainflow.types'; +import {complex} from './complex'; +import {DataHandlerCLikeFunctions as CLike, DataHandlerFunctions} from './functions.types'; + +class DataHandlerDLL extends DataHandlerFunctions +{ + + private static instance: DataHandlerDLL; + + private libPath: string; + private dllPath: string; + private lib: koffi.IKoffiLib; + + private constructor() + { + super (); + this.libPath = `${__dirname}/../brainflow/lib`; + this.dllPath = this.getDLLPath(); + this.lib = this.getLib(); + + this.getRailedPercentage = this.lib.func(CLike.get_railed_percentage); + this.performLowPass = this.lib.func(CLike.perform_lowpass); + this.performHighPass = this.lib.func(CLike.perform_highpass); + this.performBandPass = this.lib.func(CLike.perform_bandpass); + this.performBandStop = this.lib.func(CLike.perform_bandstop); + this.removeEnvironmentalNoise = this.lib.func(CLike.remove_environmental_noise); + this.writeFile = this.lib.func(CLike.write_file); + this.readFile = this.lib.func(CLike.read_file); + this.getNumElementsInFile = this.lib.func(CLike.get_num_elements_in_file); + this.performDownsampling = this.lib.func(CLike.perform_downsampling); + this.performWaveletTransform = this.lib.func(CLike.perform_wavelet_transform); + this.performInverseWaveletTransform = + this.lib.func(CLike.perform_inverse_wavelet_transform); + this.performWaveletDenoising = this.lib.func(CLike.perform_wavelet_denoising); + this.getWindow = this.lib.func(CLike.get_window); + this.performFft = this.lib.func(CLike.perform_fft); + this.performIfft = this.lib.func(CLike.perform_ifft); + this.getNearestPowerOfTwo = this.lib.func(CLike.get_nearest_power_of_two); + this.getPsd = this.lib.func(CLike.get_psd); + this.getPsdWelch = this.lib.func(CLike.get_psd_welch); + this.getBandPower = this.lib.func(CLike.get_band_power); + this.getCustomBandPowers = this.lib.func(CLike.get_custom_band_powers); + this.getOxygenLevel = this.lib.func(CLike.get_oxygen_level); + this.getHeartRate = this.lib.func(CLike.get_heart_rate); + this.restoreDataFromWaveletDetailedCoeffs = + this.lib.func(CLike.restore_data_from_wavelet_detailed_coeffs); + this.detectPeaksZScore = this.lib.func(CLike.detect_peaks_z_score); + this.performIca = this.lib.func(CLike.perform_ica); + this.getCsp = this.lib.func(CLike.get_csp); + this.detrend = this.lib.func(CLike.detrend); + this.calcStddev = this.lib.func(CLike.calc_stddev); + this.setLogLevelDataHandler = this.lib.func(CLike.set_log_level_data_handler); + this.setLogFileDataHandler = this.lib.func(CLike.set_log_file_data_handler); + this.logMessageDataHandler = this.lib.func(CLike.log_message_data_handler); + this.getVersionDataHandler = this.lib.func(CLike.get_version_data_handler); + } + + private getDLLPath() + { + const platform = os.platform(); + const arch = os.arch(); + switch (platform) + { + case 'darwin': + return `${this.libPath}/libDataHandler.dylib`; + case 'win32': + return arch === 'x64' ? `${this.libPath}/DataHandler.dll` : + `${this.libPath}/DataHandler32.dll`; + case 'linux': + return `${this.libPath}/libDataHandler.so`; + default: + throw new BrainFlowError ( + BrainFlowExitCodes.GENERAL_ERROR, `OS ${platform} is not supported.`); + } + } + + private getLib() + { + try + { + const lib = koffi.load(this.dllPath); + return lib; + } + catch (err) + { + console.error(err); + throw new BrainFlowError (BrainFlowExitCodes.GENERAL_ERROR, + `${'Could not load DataHandlerDLL DLL - path://'}${this.dllPath}`); + } + } + + public static getInstance(): DataHandlerDLL + { + if (!DataHandlerDLL.instance) + { + DataHandlerDLL.instance = new DataHandlerDLL (); + } + return DataHandlerDLL.instance; + } +} + +export class DataFilter +{ + // logging methods + public static setLogLevel(logLevel: LogLevels): void + { + const res = DataHandlerDLL.getInstance().setLogLevelDataHandler(logLevel); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not set log level properly'); + } + } + + public static setLogFile(file: string): void + { + const res = DataHandlerDLL.getInstance().setLogFileDataHandler(file); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not redirect to log file'); + } + } + + public static logMessage(logLevel: LogLevels, message: string): void + { + const res = DataHandlerDLL.getInstance().logMessageDataHandler(logLevel, message); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not writte message'); + } + } + + public static getVersion(): string + { + const len = [0]; + let out = ['\0'.repeat(512)]; + const res = DataHandlerDLL.getInstance().getVersionDataHandler(out, len, 512); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get version info'); + } + return out[0].substring(0, len[0]); + } + + // signal processing methods + public static getRailedPercentage(data: number[], gain: number): number + { + const output = [0]; + const res = + DataHandlerDLL.getInstance().getRailedPercentage(data, data.length, gain, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get railed percentage'); + } + return output[0]; + } + + public static performLowPass(data: number[], samplingRate: number, cutoff: number, + order: number, filterType: FilterTypes, ripple: number) + { + const res = DataHandlerDLL.getInstance().performLowPass( + data, data.length, samplingRate, cutoff, order, filterType, ripple); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not apply filter'); + } + } + + public static performHighPass(data: number[], samplingRate: number, cutoff: number, + order: number, filterType: FilterTypes, ripple: number) + { + const res = DataHandlerDLL.getInstance().performHighPass( + data, data.length, samplingRate, cutoff, order, filterType, ripple); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not apply filter'); + } + } + + public static performBandPass(data: number[], samplingRate: number, startFreq: number, + stopFreq: number, order: number, filterType: FilterTypes, ripple: number) + { + const res = DataHandlerDLL.getInstance().performBandPass( + data, data.length, samplingRate, startFreq, stopFreq, order, filterType, ripple); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not apply filter'); + } + } + + public static performBandStop(data: number[], samplingRate: number, startFreq: number, + stopFreq: number, order: number, filterType: FilterTypes, ripple: number) + { + const res = DataHandlerDLL.getInstance().performBandStop( + data, data.length, samplingRate, startFreq, stopFreq, order, filterType, ripple); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not apply filter'); + } + } + + public static removeEnvironmentalNoise( + data: number[], samplingRate: number, noiseType: NoiseTypes) + { + const res = DataHandlerDLL.getInstance().removeEnvironmentalNoise( + data, data.length, samplingRate, noiseType); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not apply filter'); + } + } + + public static writeFile(data: number[][], file: string, mode: string) + { + if (data.length == 0) + { + throw new BrainFlowError (BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, 'Empty data'); + } + const flat = data.flat(); + const res = + DataHandlerDLL.getInstance().writeFile(flat, data.length, data[0].length, file, mode); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not write file'); + } + } + + public static readFile(file: string): number[][] + { + const numElems = DataFilter.getNumElementsInFile(file); + const dataArr = [...new Array (numElems).fill(0)]; + const rows = [0]; + const cols = [0]; + const res = DataHandlerDLL.getInstance().readFile(dataArr, rows, cols, file, numElems); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not read file'); + } + return _.chunk(dataArr, cols[0]); + } + + private static getNumElementsInFile(file: string): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().getNumElementsInFile(file, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get info about file'); + } + return output[0]; + } + + public static performDownsampling( + data: number[], period: number, aggOperation: AggOperations): number[] + { + if (period < 1) + { + throw new BrainFlowError (BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, 'invalid period'); + } + const len = Math.trunc(data.length / period) + const output = [...new Array (len).fill(0)]; + const res = DataHandlerDLL.getInstance().performDownsampling( + data, data.length, period, aggOperation, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not perform downsampling'); + } + return output; + } + + public static performWaveletDenoising(data: number[], wavelet: WaveletTypes, + decompositionLevel: number, waveletDenoising = WaveletDenoisingTypes.SURESHRINK, + threshold = ThresholdTypes.HARD, extensionType = WaveletExtensionTypes.SYMMETRIC, + noiseLevel = NoiseEstimationLevelTypes.FIRST_LEVEL) + { + const res = DataHandlerDLL.getInstance().performWaveletDenoising(data, data.length, wavelet, + decompositionLevel, waveletDenoising, threshold, extensionType, noiseLevel); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not perform denosing'); + } + } + + public static getOxygenLevel(ppgIr: number[], ppgRed: number[], samplingRate: number, + coef1 = 1.5958422, coef2 = -34.6596622, coef3 = 112.6898759): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().getOxygenLevel( + ppgIr, ppgRed, ppgIr.length, samplingRate, coef1, coef2, coef3, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calculate oxygen level'); + } + return output[0]; + } + + public static getHeartRate( + ppgIr: number[], ppgRed: number[], samplingRate: number, fftSize: number): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().getHeartRate( + ppgIr, ppgRed, ppgIr.length, samplingRate, fftSize, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calculate heartrate'); + } + return output[0]; + } + + public static getCustomBandPowers(data: number[][], bands: number[][], channels: number[], + samplingRate: number, applyFilters = true): [number[], number[]] + { + if ((data.length == 0) || (bands.length == 0) || (channels.length == 0)) + { + throw new BrainFlowError (BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, 'Empty data'); + } + var i: number; + var j: number; + const avgBands = [...new Array (bands.length).fill(0)]; + const stddevBands = [...new Array (bands.length).fill(0)]; + const data1D = [...new Array (data[0].length * channels.length).fill(0)]; + const startFreqs = [...new Array (bands.length).fill(0)]; + const stopFreqs = [...new Array (bands.length).fill(0)]; + for (i = 0; i < bands.length; i++) + { + startFreqs[i] = bands[i][0] + stopFreqs[i] = bands[i][1] + } + for (i = 0; i < channels.length; i++) + { + for (j = 0; j < data[0].length; j++) + { + data1D[j + data[0].length * i] = data[channels[i]][j]; + } + } + const res = DataHandlerDLL.getInstance().getCustomBandPowers(data1D, channels.length, + data[0].length, startFreqs, stopFreqs, bands.length, samplingRate, + Number (applyFilters), avgBands, stddevBands); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calculate band powers'); + } + return [avgBands, stddevBands]; + } + + public static getAvgBandPowers(data: number[][], channels: number[], samplingRate: number, + applyFilters = true): [number[], number[]] + { + const bands = [[2.0, 4.0], [4.0, 8.0], [8.0, 13.0], [13.0, 30.0], [30.0, 45.0]]; + return DataFilter.getCustomBandPowers(data, bands, channels, samplingRate, applyFilters); + } + + public static getNearestPowerOfTwo(value: number): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().getNearestPowerOfTwo(value, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get nearest power'); + } + return output[0]; + } + + public static getWindow(windowFunction: WindowOperations, len: number): number[] + { + const output = [...new Array (len).fill(0)]; + const res = DataHandlerDLL.getInstance().getWindow(windowFunction, len, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get window'); + } + return output; + } + + public static performFft(data: number[], windowType: WindowOperations): complex[] + { + var i: number; + if (data.length % 2 != 0) + { + throw new BrainFlowError ( + BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, "invalid input length"); + } + const outputLen = Math.trunc(data.length / 2 + 1); + const outputRe = [...new Array (outputLen).fill(0)]; + const outputIm = [...new Array (outputLen).fill(0)]; + const res = DataHandlerDLL.getInstance().performFft( + data, data.length, windowType, outputRe, outputIm); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc fft'); + } + const output: complex[] = []; + for (i = 0; i < outputLen; i++) + { + output.push(new complex (outputRe[i], outputIm[i])); + } + return output; + } + + public static performIfft(data: complex[]): number[] + { + var i: number; + const output = [...new Array (2 * (data.length - 1)).fill(0)]; + const tempRe = [...new Array (data.length).fill(0)]; + const tempIm = [...new Array (data.length).fill(0)]; + for (i = 0; i < data.length; i++) + { + tempRe[i] = data[i].real; + tempIm[i] = data[i].img; + } + const res = DataHandlerDLL.getInstance().performIfft(tempRe, tempIm, output.length, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc ifft'); + } + + return output; + } + + public static getPsd( + data: number[], samplingRate: number, windowType: WindowOperations): [number[], number[]] + { + if (data.length % 2 != 0) + { + throw new BrainFlowError ( + BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, "invalid input length"); + } + const outputLen = Math.trunc(data.length / 2 + 1); + const ampls = [...new Array (outputLen).fill(0)]; + const freqs = [...new Array (outputLen).fill(0)]; + const res = DataHandlerDLL.getInstance().getPsd( + data, data.length, samplingRate, windowType, ampls, freqs); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc psd'); + } + return [ampls, freqs]; + } + + public static getPsdWelch(data: number[], nfft: number, overlap: number, samplingRate: number, + windowType: WindowOperations): [number[], number[]] + { + if (data.length % 2 != 0) + { + throw new BrainFlowError ( + BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, "invalid input length"); + } + const outputLen = Math.trunc(data.length / 2 + 1); + const ampls = [...new Array (outputLen).fill(0)]; + const freqs = [...new Array (outputLen).fill(0)]; + const res = DataHandlerDLL.getInstance().getPsdWelch( + data, data.length, nfft, overlap, samplingRate, windowType, ampls, freqs); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc psd'); + } + return [ampls, freqs]; + } + + public static getBandPower( + psd: [number[], number[]], startFreq: number, stopFreq: number): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().getBandPower( + psd[0], psd[1], psd[0].length, startFreq, stopFreq, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc band power'); + } + return output[0]; + } + + public static performWaveletTransform(data: number[], wavelet: WaveletTypes, + decompositionLevel: number, extension: WaveletExtensionTypes): [number[], number[]] + { + const waveletCoeffs = [...new Array (data.length + 2 * (40 + 1)).fill(0)]; + const lengths = [...new Array (decompositionLevel + 1).fill(0)]; + const res = DataHandlerDLL.getInstance().performWaveletTransform( + data, data.length, wavelet, decompositionLevel, extension, waveletCoeffs, lengths); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc wavelet transform'); + } + const sum = lengths.reduce((a: number, b: number) => { return a + b; }, 0); + const coeffsNew = waveletCoeffs.slice(0, sum); + return [coeffsNew, lengths]; + } + + public static performInverseWaveletTransform(waveletData: [number[], number[]], + originalLen: number, wavelet: WaveletTypes, decompositionLevel: number, + extension: WaveletExtensionTypes): number[] + { + const output = [...new Array (originalLen).fill(0)]; + const res = DataHandlerDLL.getInstance().performInverseWaveletTransform(waveletData[0], + originalLen, wavelet, decompositionLevel, extension, waveletData[1], output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc inverse wavelet transform'); + } + return output; + } + + public static restoreDataFromWaveletDetailedCoeffs(data: number[], wavelet: WaveletTypes, + decompositionLevel: number, levelToRestore: number): number[] + { + const output = [...new Array (data.length).fill(0)]; + const res = DataHandlerDLL.getInstance().restoreDataFromWaveletDetailedCoeffs( + data, data.length, wavelet, decompositionLevel, levelToRestore, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not restore data from wavelet'); + } + return output; + } + + public static detectPeaksZScore( + data: number[], lag = 5, threshold = 3.5, influence = 0.1): number[] + { + const output = [...new Array (data.length).fill(0)]; + const res = DataHandlerDLL.getInstance().detectPeaksZScore( + data, data.length, lag, threshold, influence, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not detect peaks'); + } + return output; + } + + public static performIca(data: number[][], numComponents: number, + channels: number[]): [number[][], number[][], number[][], number[][]] + { + if (data.length < 1) + { + throw new BrainFlowError (BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR, "empty data"); + } + var i: number; + var j: number; + const data1D = [...new Array (data[0].length * channels.length).fill(0)]; + const w = [...new Array (numComponents * numComponents).fill(0)]; + const k = [...new Array (channels.length * numComponents).fill(0)]; + const a = [...new Array (numComponents * channels.length).fill(0)]; + const s = [...new Array (data[0].length * numComponents).fill(0)]; + + for (i = 0; i < channels.length; i++) + { + for (j = 0; j < data[0].length; j++) + { + data1D[j + data[0].length * i] = data[channels[i]][j]; + } + } + + const res = DataHandlerDLL.getInstance().performIca( + data1D, channels.length, data[0].length, numComponents, w, k, a, s); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not perform ica'); + } + const wOut: number[][] = []; + while (w.length) + wOut.push(w.splice(0, numComponents)); + const kOut: number[][] = []; + while (k.length) + kOut.push(k.splice(0, channels.length)); + const aOut: number[][] = []; + while (a.length) + aOut.push(a.splice(0, numComponents)); + const sOut: number[][] = []; + while (s.length) + sOut.push(s.splice(0, data[0].length)); + return [wOut, kOut, aOut, sOut]; + } + + public static detrend(data: number[], detrendOperation: DetrendOperations) + { + const res = DataHandlerDLL.getInstance().detrend(data, data.length, detrendOperation); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not detrend'); + } + } + + public static calcStddev(data: number[], startPos: number, stopPos: number): number + { + const output = [0]; + const res = DataHandlerDLL.getInstance().calcStddev(data, startPos, stopPos, output); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not calc stddev'); + } + return output[0]; + } +} \ No newline at end of file diff --git a/nodejs_package/brainflow/functions.types.ts b/nodejs_package/brainflow/functions.types.ts new file mode 100644 index 000000000..9bdefd98c --- /dev/null +++ b/nodejs_package/brainflow/functions.types.ts @@ -0,0 +1,466 @@ +import { + AggOperations, + BoardIds, + BrainFlowExitCodes, + BrainFlowPresets, + FilterTypes, + LogLevels, + NoiseEstimationLevelTypes, + NoiseTypes, + ThresholdTypes, + WaveletDenoisingTypes, + WaveletExtensionTypes, + WaveletTypes, + WindowOperations +} from './brainflow.types'; + +export enum BoardControllerCLikeFunctions { + // logging and version methods + set_log_level_board_controller = 'int set_log_level_board_controller (int log_level)', + set_log_file_board_controller = 'int set_log_file_board_controller (const char *log_file)', + log_message_board_controller = + 'int log_message_board_controller (int log_level, char *log_message)', + get_version_board_controller = + 'int get_version_board_controller (_Inout_ char *version, _Inout_ int *len, int max)', + // board methods + start_stream = + 'int start_stream (int buffer_size, const char *streamer_params, int board_id, const char *json_brainflow_input_params)', + stop_stream = 'int stop_stream (int board_id, const char *json_brainflow_input_params)', + prepare_session = 'int prepare_session (int board_id, const char *json_brainflow_input_params)', + release_all_sessions = 'int release_all_sessions ()', + release_session = 'int release_session (int board_id, const char *json_brainflow_input_params)', + add_streamer = + 'int add_streamer (const char *streamer, int preset, int board_id, const char *json_brainflow_input_params)', + config_board = + 'int config_board (const char *config, _Inout_ char *response, _Inout_ int *resp_len, int board_id, const char *json_brainflow_input_params)', + delete_streamer = + 'int delete_streamer (const char *streamer, int preset, int board_id, const char *json_brainflow_input_params)', + insert_marker = + 'int insert_marker (double value, int preset, int board_id, const char *json_brainflow_input_params)', + is_prepared = + 'int is_prepared (_Inout_ int *prepared, int board_id, const char *json_brainflow_input_params)', + get_board_data_count = + 'int get_board_data_count (int preset, _Inout_ int *result, int board_id, const char *json_brainflow_input_params)', + get_board_data = + 'int get_board_data (int data_count, int preset, _Inout_ double *data_buf, int board_id, const char *json_brainflow_input_params)', + get_current_board_data = + 'int get_current_board_data (int num_samples, int preset, _Inout_ double *data_buf, _Inout_ int *returned_samples, int board_id, const char *json_brainflow_input_params)', + // board info getter methods + get_num_rows = 'int get_num_rows (int board_id, int preset, _Inout_ int *num_rows)', + get_sampling_rate = + 'int get_sampling_rate (int board_id, int preset, _Inout_ int *sampling_rate)', + get_battery_channel = 'int get_battery_channel (int board_id, int preset, _Inout_ int *value)', + get_package_num_channel = + 'int get_package_num_channel (int board_id, int preset, _Inout_ int *value)', + get_timestamp_channel = + 'int get_timestamp_channel (int board_id, int preset, _Inout_ int *value)', + get_marker_channel = 'int get_marker_channel (int board_id, int preset, _Inout_ int *value)', + get_eeg_channels = + 'int get_eeg_channels (int board_id, int preset, _Inout_ int *eeg_channels, _Inout_ int *len)', + get_exg_channels = + 'int get_exg_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_emg_channels = + 'int get_emg_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_ecg_channels = + 'int get_ecg_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_eog_channels = + 'int get_eog_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_ppg_channels = + 'int get_ppg_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_eda_channels = + 'int get_eda_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_accel_channels = + 'int get_accel_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_analog_channels = + 'int get_analog_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_gyro_channels = + 'int get_gyro_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_other_channels = + 'int get_other_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_temperature_channels = + 'int get_temperature_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_resistance_channels = + 'int get_resistance_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_magnetometer_channels = + 'int get_magnetometer_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_rotation_channels = + 'int get_rotation_channels (int board_id, int preset, _Inout_ int *channels, _Inout_ int *len)', + get_eeg_names = + 'int get_eeg_names (int board_id, int preset, _Inout_ char *eeg_names, _Inout_ int *len)', + get_device_name = + 'int get_device_name (int board_id, int preset, _Inout_ char *device_name, _Inout_ int *len)', + get_board_descr = + 'int get_board_descr (int board_id, int preset, _Inout_ char *descr, _Inout_ int *len)', + get_board_presets = + 'int get_board_presets (int board_id, _Inout_ int *presets, _Inout_ int *len)', +} + +export class BoardControllerFunctions +{ + // logging and version methods + setLogLevelBoardController!: (logLevel: LogLevels) => BrainFlowExitCodes; + setLogFileBoardController!: (logFile: string) => BrainFlowExitCodes; + logMessageBoardController!: (logLevel: LogLevels, logMessage: string) => BrainFlowExitCodes; + getVersionBoardController!: ( + version: string[], + len: number[], + maxLen: number, + ) => BrainFlowExitCodes; + // board methods + releaseAllSessions!: () => BrainFlowExitCodes; + releaseSession!: (boardId: BoardIds, inputJson: string) => BrainFlowExitCodes; + stopStream!: (boardId: BoardIds, inputJson: string) => BrainFlowExitCodes; + addStreamer!: ( + streamer: string, + preset: BrainFlowPresets, + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + deleteStreamer!: ( + streamer: string, + preset: BrainFlowPresets, + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + insertMarker!: (value: number, preset: BrainFlowPresets, boardId: BoardIds, + inputJson: string) => BrainFlowExitCodes; + isPrepared!: (prepared: number[], boardId: BoardIds, inputJson: string) => BrainFlowExitCodes; + prepareSession!: (boardId: BoardIds, inputJson: string) => BrainFlowExitCodes; + startStream!: ( + numSamples: number, + streamerParams: string|null, + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + configBoard!: ( + config: string, + response: string[], + responseLen: number[], + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + getBoardDataCount!: ( + preset: BrainFlowPresets, + dataSize: number[], + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + getBoardData!: ( + dataSize: number, + preset: BrainFlowPresets, + dataArr: number[], + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + getCurrentBoardData!: ( + numSamples: number, + preset: BrainFlowPresets, + dataBuf: number[], + returnedSamples: number[], + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; + // board info getter methods + getNumRows!: ( + boardId: BoardIds, preset: BrainFlowPresets, numRows: number[]) => BrainFlowExitCodes; + getTimestampChannel!: ( + boardId: BoardIds, preset: BrainFlowPresets, numRows: number[]) => BrainFlowExitCodes; + getPackageNumChannel!: ( + boardId: BoardIds, preset: BrainFlowPresets, numRows: number[]) => BrainFlowExitCodes; + getMarkerChannel!: ( + boardId: BoardIds, preset: BrainFlowPresets, numRows: number[]) => BrainFlowExitCodes; + getBatteryChannel!: ( + boardId: BoardIds, preset: BrainFlowPresets, numRows: number[]) => BrainFlowExitCodes; + getSamplingRate!: ( + boardId: BoardIds, preset: BrainFlowPresets, samplingRate: number[]) => BrainFlowExitCodes; + getEegChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + eegChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getExgChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + exgChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getEmgChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + emgChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getEogChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + eogChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getEcgChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + ecgChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getPpgChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + ppgChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getEdaChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + edaChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getAccelChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + accelChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getAnalogChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + analogChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getGyroChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + gyroChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getOtherChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + otherChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getRotationChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + channels: number[], + len: number[], + ) => BrainFlowExitCodes; + getTemperatureChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + temperatureChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getResistanceChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + resistanceChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getMagnetometerChannels!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + magnetometerChannels: number[], + len: number[], + ) => BrainFlowExitCodes; + getEegNames!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + names: string[], + len: number[], + ) => BrainFlowExitCodes; + getDeviceName!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + name: string[], + len: number[], + ) => BrainFlowExitCodes; + getBoardPresets!: ( + boardId: BoardIds, + presets: number[], + len: number[], + ) => BrainFlowExitCodes; + getBoardDescr!: ( + boardId: BoardIds, + preset: BrainFlowPresets, + descr: string[], + len: number[], + ) => BrainFlowExitCodes; +} + +export enum DataHandlerCLikeFunctions { + // signal processing methods + perform_lowpass = + 'int perform_lowpass (_Inout_ double *data, int data_len, int sampling_rate, double cutoff, int order, int filter_type, double ripple)', + perform_highpass = + 'int perform_highpass (_Inout_ double *data, int data_len, int sampling_rate, double cutoff, int order, int filter_type, double ripple)', + perform_bandpass = + 'int perform_bandpass (_Inout_ double *data, int data_len, int sampling_rate, double start_freq, double stop_freq, int order, int filter_type, double ripple)', + perform_bandstop = + 'int perform_bandstop (_Inout_ double *data, int data_len, int sampling_rate, double start_freq, double stop_freq, int order, int filter_type, double ripple)', + remove_environmental_noise = + 'int remove_environmental_noise (_Inout_ double *data, int data_len, int sampling_rate, int noise_type)', + write_file = + 'int write_file (const double *data, int num_rows, int num_cols, const char *file_name, const char *file_mode)', + read_file = + 'int read_file (_Inout_ double *data, _Inout_ int *num_rows, _Inout_ int *num_cols, const char *file_name, int num_elements)', + get_num_elements_in_file = + 'int get_num_elements_in_file (const char *file_name, _Inout_ int *num_elements)', + perform_downsampling = + 'int perform_downsampling (double *data, int data_len, int period, int agg_operation, _Inout_ double *output_data)', + perform_wavelet_transform = + 'int perform_wavelet_transform (double *data, int data_len, int wavelet, int decomposition_level, int extension, _Inout_ double *output_data, _Inout_ int *decomposition_lengths)', + perform_inverse_wavelet_transform = + 'int perform_inverse_wavelet_transform (double *wavelet_coeffs, int original_data_len, int wavelet, int decomposition_level, int extension, int *decomposition_lengths, _Inout_ double *output_data)', + perform_wavelet_denoising = + 'int perform_wavelet_denoising (_Inout_ double *data, int data_len, int wavelet, int decomposition_level, int wavelet_denoising, int threshold, int extenstion_type, int noise_level)', + get_window = + 'int get_window (int window_function, int window_len, _Inout_ double *output_window)', + perform_fft = + 'int perform_fft (double *data, int data_len, int window_function, _Inout_ double *output_re, _Inout_ double *output_im)', + perform_ifft = + 'int perform_ifft (double *input_re, double *input_im, int data_len, _Inout_ double *restored_data)', + get_nearest_power_of_two = 'int get_nearest_power_of_two (int value, _Inout_ int *output)', + get_psd = + 'int get_psd (double *data, int data_len, int sampling_rate, int window_function, _Inout_ double *output_ampl, _Inout_ double *output_freq)', + detrend = 'int detrend (_Inout_ double *data, int data_len, int detrend_operation)', + calc_stddev = + 'int calc_stddev (double *data, int start_pos, int end_pos, _Inout_ double *output)', + get_psd_welch = + 'int get_psd_welch (double *data, int data_len, int nfft, int overlap, int sampling_rate, int window_function, _Inout_ double *output_ampl, _Inout_ double *output_freq)', + get_band_power = + 'int get_band_power (double *ampl, double *freq, int data_len, double freq_start, double freq_end, _Inout_ double *band_power)', + get_custom_band_powers = + 'int get_custom_band_powers (double *raw_data, int rows, int cols, double *start_freqs, double *stop_freqs, int num_bands, int sampling_rate, int apply_filters, _Inout_ double *avg_band_powers, _Inout_ double *stddev_band_powers)', + get_oxygen_level = + 'int get_oxygen_level (double *ppg_ir, double *ppg_red, int data_size, int sampling_rate, double callib_coef1, double callib_coef2, double callib_coef3, _Inout_ double *oxygen_level)', + get_heart_rate = + 'int get_heart_rate (double *ppg_ir, double *ppg_red, int data_size, int sampling_rate, int fft_size, _Inout_ double *rate)', + restore_data_from_wavelet_detailed_coeffs = + 'int restore_data_from_wavelet_detailed_coeffs (double *data, int data_len, int wavelet, int decomposition_level, int level_to_restore, _Inout_ double *output)', + detect_peaks_z_score = + 'int detect_peaks_z_score (double *data, int data_len, int lag, double threshold, double influence, _Inout_ double *output)', + perform_ica = + 'int perform_ica (double *data, int rows, int cols, int num_components, _Inout_ double *w_mat, _Inout_ double *k_mat, _Inout_ double *a_mat, _Inout_ double *s_mat)', + get_csp = + 'int get_csp (const double *data, const double *labels, int n_epochs, int n_channels, int n_times, _Inout_ double *output_w, _Inout_ double *output_d)', + get_railed_percentage = + 'int get_railed_percentage (double *raw_data, int data_len, int gain, _Inout_ double *output)', + // logging methods + set_log_level_data_handler = 'int set_log_level_data_handler (int log_level)', + set_log_file_data_handler = 'int set_log_file_data_handler (const char *log_file)', + log_message_data_handler = 'int log_message_data_handler (int log_level, char *message)', + get_version_data_handler = + 'int get_version_data_handler (_Inout_ char *version, _Inout_ int *num_chars, int max_chars)' +} + +export class DataHandlerFunctions +{ + // signal processing methods + getRailedPercentage!: ( + rawData: number[], dataLen: number, gain: number, output: number[]) => BrainFlowExitCodes; + performLowPass!: (rawData: number[], dataLen: number, samplingRate: number, cutoff: number, + order: number, filterType: FilterTypes, ripple: number) => BrainFlowExitCodes; + performHighPass!: (rawData: number[], dataLen: number, samplingRate: number, cutoff: number, + order: number, filterType: FilterTypes, ripple: number) => BrainFlowExitCodes; + performBandPass!: (rawData: number[], dataLen: number, samplingRate: number, startFreq: number, + stopFreq: number, order: number, filterType: FilterTypes, + ripple: number) => BrainFlowExitCodes; + performBandStop!: (rawData: number[], dataLen: number, samplingRate: number, startFreq: number, + stopFreq: number, order: number, filterType: FilterTypes, + ripple: number) => BrainFlowExitCodes; + removeEnvironmentalNoise!: (rawData: number[], dataLen: number, samplingRate: number, + noiseType: NoiseTypes) => BrainFlowExitCodes; + writeFile!: (data: number[], rows: number, cols: number, file: string, + mode: string) => BrainFlowExitCodes; + readFile!: (data: number[], rows: number[], cols: number[], file: string, + numElems: number) => BrainFlowExitCodes; + getNumElementsInFile!: (file: string, numElems: number[]) => BrainFlowExitCodes; + performDownsampling!: (data: number[], dataLen: number, period: number, + aggOperation: AggOperations, output: number[]) => BrainFlowExitCodes; + performWaveletTransform!: (data: number[], dataLen: number, wavelet: WaveletTypes, + decompositionLevel: number, extension: WaveletExtensionTypes, outputData: number[], + decompositionLengths: number[]) => BrainFlowExitCodes; + performInverseWaveletTransform!: (waveletCoeffs: number[], originalDataLen: number, + wavelet: WaveletTypes, decompositionLevel: number, extension: WaveletExtensionTypes, + decompositionLengths: number[], outputData: number[]) => BrainFlowExitCodes; + performWaveletDenoising!: (data: number[], dataLen: number, wavelet: WaveletTypes, + decompositionLevel: number, waveletDenoising: WaveletDenoisingTypes, + threshold: ThresholdTypes, extenstionType: WaveletExtensionTypes, + noiseLevel: NoiseEstimationLevelTypes) => BrainFlowExitCodes; + getWindow!: (windowFunction: WindowOperations, windowLen: number, + outputWindow: number[]) => BrainFlowExitCodes; + performFft!: (data: number[], dataLen: number, windowFunction: WindowOperations, + outputRe: number[], outputIm: number[]) => BrainFlowExitCodes; + performIfft!: (inputRe: number[], inputIm: number[], dataLen: number, + restoredData: number[]) => BrainFlowExitCodes; + getNearestPowerOfTwo!: (value: number, output: number[]) => BrainFlowExitCodes; + getPsd!: (data: number[], dataLen: number, samplingRate: number, + windowFunction: WindowOperations, outputAmpl: number[], + outputFreq: number[]) => BrainFlowExitCodes; + getPsdWelch!: (data: number[], dataLen: number, nfft: number, overlap: number, + samplingRate: number, windowFunction: WindowOperations, outputAmpl: number[], + outputFreq: number[]) => BrainFlowExitCodes; + getBandPower!: (ampl: number[], freq: number[], dataLen: number, freqStart: number, + freqEnd: number, bandPower: number[]) => BrainFlowExitCodes; + getCustomBandPowers!: (data: number[], rows: number, cols: number, startFreqs: number[], + stopFreqs: number[], numBands: number, samplingRate: number, applyFilters: number, + avgBandPowers: number[], stddevBandPowers: number[]) => BrainFlowExitCodes; + getOxygenLevel!: (ppgIr: number[], ppgRed: number[], dataSize: number, samplingRate: number, + callibCoef1: number, callibCoef2: number, callibCoef3: number, + oxygenLevel: number[]) => BrainFlowExitCodes; + getHeartRate!: (ppgIr: number[], ppgRed: number[], dataSize: number, samplingRate: number, + fftSize: number, rate: number[]) => BrainFlowExitCodes; + restoreDataFromWaveletDetailedCoeffs!: (data: number[], dataLen: number, wavelet: number, + decompositionLevel: number, levelToRestore: number, output: number[]) => BrainFlowExitCodes; + detectPeaksZScore!: (data: number[], dataLen: number, lag: number, threshold: number, + influence: number, output: number[]) => BrainFlowExitCodes; + performIca!: (data: number[], rows: number, cols: number, numComponents: number, wMat: number[], + kMat: number[], aMat: number[], sMat: number[]) => BrainFlowExitCodes; + getCsp!: (data: number[], labels: number[], nEpochs: number, nChannels: number, nTimes: number, + outputW: number[], outputD: number[]) => BrainFlowExitCodes; + detrend!: (rawData: number[], dataLen: number, detrendOperation: number) => BrainFlowExitCodes; + calcStddev!: (rawData: number[], startPos: number, stopPos: number, + output: number[]) => BrainFlowExitCodes; + // logging methods + setLogLevelDataHandler!: (logLevel: LogLevels) => BrainFlowExitCodes; + setLogFileDataHandler!: (logFile: string) => BrainFlowExitCodes; + logMessageDataHandler!: (logLevel: LogLevels, logMessage: string) => BrainFlowExitCodes; + getVersionDataHandler!: ( + version: string[], + len: number[], + maxLen: number, + ) => BrainFlowExitCodes; +} + +export enum MLModuleCLikeFunctions { + // logging and version methods + set_log_level_ml_module = 'int set_log_level_ml_module (int log_level)', + set_log_file_ml_module = 'int set_log_file_ml_module (const char *log_file)', + log_message_ml_module = 'int log_message_ml_module (int log_level, char *log_message)', + get_version_ml_module = + 'int get_version_ml_module (_Inout_ char *version, _Inout_ int *len, int max)', + prepare = 'int prepare (const char *json_params)', + predict = + 'int predict (double *data, int data_len, _Inout_ double *output, _Inout_ int *output_len, const char *json_params)', + release = 'int release (const char *json_params)', + release_all = 'int release_all ()' +} + +export class MLModuleFunctions +{ + // logging and version methods + setLogLevelMLModule!: (logLevel: LogLevels) => BrainFlowExitCodes; + setLogFileMLModule!: (logFile: string) => BrainFlowExitCodes; + logMessageMLModule!: (logLevel: LogLevels, logMessage: string) => BrainFlowExitCodes; + getVersionMLModule!: ( + version: string[], + len: number[], + maxLen: number, + ) => BrainFlowExitCodes; + prepare!: (inputJson: string) => BrainFlowExitCodes; + predict!: (data: number[], dataLen: number, output: number[], outputLen: number[], + inputJson: string) => BrainFlowExitCodes; + releaseAll!: () => BrainFlowExitCodes; + release!: (inputJson: string) => BrainFlowExitCodes; +} \ No newline at end of file diff --git a/nodejs_package/brainflow/index.ts b/nodejs_package/brainflow/index.ts new file mode 100644 index 000000000..e4de4b747 --- /dev/null +++ b/nodejs_package/brainflow/index.ts @@ -0,0 +1,5 @@ +export * from './board_shim'; +export * from './brainflow.types'; +export * from './data_filter'; +export * from './complex'; +export * from './ml_model'; \ No newline at end of file diff --git a/nodejs_package/brainflow/ml_model.ts b/nodejs_package/brainflow/ml_model.ts new file mode 100644 index 000000000..7676780fd --- /dev/null +++ b/nodejs_package/brainflow/ml_model.ts @@ -0,0 +1,205 @@ +import koffi from 'koffi'; +import _ from 'lodash'; +import * as os from 'os'; + +import { + BrainFlowClassifiers, + BrainFlowError, + BrainFlowExitCodes, + BrainFlowMetrics, + IBrainFlowModelParams, + LogLevels, +} from './brainflow.types'; +import {MLModuleCLikeFunctions as CLike, MLModuleFunctions} from './functions.types'; + +export class BrainFlowModelParams +{ + public inputParams: IBrainFlowModelParams = { + metric: BrainFlowMetrics.USER_DEFINED, + classifier: BrainFlowClassifiers.ONNX_CLASSIFIER, + file: '', + otherInfo: '', + outputName: '', + maxArraySize: 8192 + }; + + constructor(metric: BrainFlowMetrics, classifier: BrainFlowClassifiers, + inputParams: Partial) + { + this.inputParams = {...this.inputParams, ...inputParams }; + this.inputParams.metric = metric; + this.inputParams.classifier = classifier; + } + + public toJson(): string + { + const params: Record = {}; + Object.keys(this.inputParams).forEach((key) => { + params[_.snakeCase(key)] = this.inputParams[key as keyof IBrainFlowModelParams]; + }); + return JSON.stringify(params); + } +} + +class MLModuleDLL extends MLModuleFunctions +{ + private static instance: MLModuleDLL; + + private libPath: string; + private dllPath: string; + private lib: koffi.IKoffiLib; + + private constructor() + { + super (); + this.libPath = `${__dirname}/../brainflow/lib`; + this.dllPath = this.getDLLPath(); + this.lib = this.getLib(); + + this.setLogLevelMLModule = this.lib.func(CLike.set_log_level_ml_module); + this.setLogFileMLModule = this.lib.func(CLike.set_log_file_ml_module); + this.logMessageMLModule = this.lib.func(CLike.log_message_ml_module); + this.getVersionMLModule = this.lib.func(CLike.get_version_ml_module); + this.prepare = this.lib.func(CLike.prepare); + this.predict = this.lib.func(CLike.predict); + this.release = this.lib.func(CLike.release); + this.releaseAll = this.lib.func(CLike.release_all); + } + + private getDLLPath() + { + const platform = os.platform(); + const arch = os.arch(); + switch (platform) + { + case 'darwin': + return `${this.libPath}/libMLModule.dylib`; + case 'win32': + return arch === 'x64' ? `${this.libPath}/MLModule.dll` : + `${this.libPath}/MLModule32.dll`; + case 'linux': + return `${this.libPath}/libMLModule.so`; + default: + throw new BrainFlowError ( + BrainFlowExitCodes.GENERAL_ERROR, `OS ${platform} is not supported.`); + } + } + + private getLib() + { + try + { + const lib = koffi.load(this.dllPath); + return lib; + } + catch (err) + { + console.error(err); + throw new BrainFlowError (BrainFlowExitCodes.GENERAL_ERROR, + `${'Could not load MLModule DLL - path://'}${this.dllPath}`); + } + } + + public static getInstance(): MLModuleDLL + { + if (!MLModuleDLL.instance) + { + MLModuleDLL.instance = new MLModuleDLL (); + } + return MLModuleDLL.instance; + } +} + +export class MLModel +{ + private inputJson: string; + private input: BrainFlowModelParams; + + constructor(metric: BrainFlowMetrics, classifier: BrainFlowClassifiers, + inputParams: Partial) + { + this.input = new BrainFlowModelParams (metric, classifier, inputParams); + this.inputJson = this.input.toJson(); + } + + // logging methods + public static getVersion(): string + { + const len = [0]; + let out = ['\0'.repeat(512)]; + const res = MLModuleDLL.getInstance().getVersionMLModule(out, len, 512); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not get version info'); + } + return out[0].substring(0, len[0]); + } + + public static setLogLevel(logLevel: LogLevels): void + { + const res = MLModuleDLL.getInstance().setLogLevelMLModule(logLevel); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not set log level properly'); + } + } + + public static setLogFile(file: string): void + { + const res = MLModuleDLL.getInstance().setLogFileMLModule(file); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not redirect to log file'); + } + } + + public static logMessage(logLevel: LogLevels, message: string): void + { + const res = MLModuleDLL.getInstance().logMessageMLModule(logLevel, message); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not writte message'); + } + } + + // model methods + public prepare(): void + { + const res = MLModuleDLL.getInstance().prepare(this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not prepare model'); + } + } + + public predict(data: number[]): number[] + { + const len = [0]; + const output = [...new Array (this.input.inputParams.maxArraySize).fill(0)]; + const res = + MLModuleDLL.getInstance().predict(data, data.length, output, len, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not predict'); + } + return output.slice(0, len[0]); + } + + public release(): void + { + const res = MLModuleDLL.getInstance().release(this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not release model'); + } + } + + public static releaseAll(): void + { + const res = MLModuleDLL.getInstance().releaseAll(); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not release models'); + } + } +} diff --git a/nodejs_package/jest.config.js b/nodejs_package/jest.config.js new file mode 100644 index 000000000..2ea13b70b --- /dev/null +++ b/nodejs_package/jest.config.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + testEnvironment: "node", + preset: "ts-jest", +}; diff --git a/nodejs_package/package.json b/nodejs_package/package.json new file mode 100644 index 000000000..28740b1d4 --- /dev/null +++ b/nodejs_package/package.json @@ -0,0 +1,54 @@ +{ + "name": "brainflow", + "version": "0.0.0-development", + "description": "JS Binding for BrainFlow", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "lint": "eslint './brainflow/**/*.{js,ts,tsx}'", + "test": "jest", + "test:watch": "jest --watchAll", + "build": "tsc", + "watch": "tsc -w" + }, + "repository": { + "type": "git", + "url": "https://github.com/brainflow-dev/brainflow" + }, + "keywords": [ + "TypeScript", + "JavaScript", + "Brainflow" + ], + "author": { + "name": "Andrey Parfenov", + "email": "a1994ndrey@gmail.com" + }, + "license": "MIT", + "devDependencies": { + "@types/jest": "29.5.3", + "@types/lodash": "4.14.195", + "@types/node": "20.4.2", + "@typescript-eslint/eslint-plugin": "^5.50.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "eslint-config-prettier": "8.8.0", + "eslint-config-standard-with-typescript": "36.1.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-prettier": "5.0.0", + "eslint-plugin-promise": "6.0.0", + "jest": "29.6.1", + "prettier": "3.0.0", + "ts-jest": "29.1.1", + "typescript": "^5.1.6" + }, + "files": [ + "dist/**/*", + "brainflow/lib/*" + ], + "dependencies": { + "koffi": "2.5.7", + "lodash": "4.17.21" + } +} diff --git a/nodejs_package/tests/bandpower.ts b/nodejs_package/tests/bandpower.ts new file mode 100644 index 000000000..0c88506bf --- /dev/null +++ b/nodejs_package/tests/bandpower.ts @@ -0,0 +1,27 @@ +import {BoardIds, BoardShim, DataFilter, WindowOperations} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (5000); + board.stopStream(); + const data = board.getCurrentBoardData(128); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const samplingRate = BoardShim.getSamplingRate(boardId); + const oldData = data[eegChannels[1]]; + const psd = DataFilter.getPsdWelch(oldData, 64, 0.5, samplingRate, WindowOperations.HAMMING); + const alpha = DataFilter.getBandPower(psd, 7.0, 13.0); + const beta = DataFilter.getBandPower(psd, 14.0, 30.0); + console.info(alpha / beta); +} + +runExample (); diff --git a/nodejs_package/tests/bandpower_all.ts b/nodejs_package/tests/bandpower_all.ts new file mode 100644 index 000000000..b56172204 --- /dev/null +++ b/nodejs_package/tests/bandpower_all.ts @@ -0,0 +1,25 @@ +import {BoardIds, BoardShim, DataFilter} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (4000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const samplingRate = BoardShim.getSamplingRate(boardId); + const bandPowers = + DataFilter.getAvgBandPowers(data, [eegChannels[0], eegChannels[1]], samplingRate) + console.info(bandPowers); +} + +runExample (); diff --git a/nodejs_package/tests/brainflow_get_data.ts b/nodejs_package/tests/brainflow_get_data.ts new file mode 100644 index 000000000..104280997 --- /dev/null +++ b/nodejs_package/tests/brainflow_get_data.ts @@ -0,0 +1,21 @@ +import {BoardIds, BoardShim} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const board = new BoardShim (BoardIds.SYNTHETIC_BOARD, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession(); + console.info('Data'); + console.info(data); +} + +runExample (); diff --git a/nodejs_package/tests/denoising.ts b/nodejs_package/tests/denoising.ts new file mode 100644 index 000000000..c161ea4fb --- /dev/null +++ b/nodejs_package/tests/denoising.ts @@ -0,0 +1,25 @@ +import {BoardIds, BoardShim, DataFilter, WaveletTypes} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (5000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const oldData = data[eegChannels[0]]; + console.info(oldData); + DataFilter.performWaveletDenoising(oldData, WaveletTypes.DB2, 2); + console.info(oldData); +} + +runExample (); diff --git a/nodejs_package/tests/downsampling.ts b/nodejs_package/tests/downsampling.ts new file mode 100644 index 000000000..cd9837f29 --- /dev/null +++ b/nodejs_package/tests/downsampling.ts @@ -0,0 +1,25 @@ +import {AggOperations, BoardIds, BoardShim, DataFilter} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getCurrentBoardData(10); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const oldData = data[eegChannels[0]]; + console.info(oldData); + const newData = DataFilter.performDownsampling(oldData, 3, AggOperations.MEAN); + console.info(newData); +} + +runExample (); diff --git a/nodejs_package/tests/eeg_metrics.ts b/nodejs_package/tests/eeg_metrics.ts new file mode 100644 index 000000000..366d45483 --- /dev/null +++ b/nodejs_package/tests/eeg_metrics.ts @@ -0,0 +1,36 @@ +import { + BoardIds, + BoardShim, + BrainFlowClassifiers, + BrainFlowMetrics, + DataFilter, + MLModel +} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession() + console.info(data); + const eegChannels = BoardShim.getEegChannels(boardId); + const samplingRate = BoardShim.getSamplingRate(boardId); + const bands = DataFilter.getAvgBandPowers(data, eegChannels, samplingRate, true); + const model = + new MLModel (BrainFlowMetrics.RESTFULNESS, BrainFlowClassifiers.DEFAULT_CLASSIFIER, {}); + model.prepare(); + console.info(model.predict(bands[0])); + model.release(); +} + +runExample (); diff --git a/nodejs_package/tests/ica.ts b/nodejs_package/tests/ica.ts new file mode 100644 index 000000000..ef5c728b8 --- /dev/null +++ b/nodejs_package/tests/ica.ts @@ -0,0 +1,27 @@ +import {BoardIds, BoardShim, DataFilter} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (10000); + board.stopStream(); + const data = board.getCurrentBoardData(500); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const eegData = data[eegChannels[0]]; + const eeg2D: number[][] = []; + while (eegData.length) + eeg2D.push(eegData.splice(0, 100)); + const icaData = DataFilter.performIca(eeg2D, 2, [0, 1, 2, 3, 4]); + console.info(icaData[3]); +} + +runExample (); diff --git a/nodejs_package/tests/markers.ts b/nodejs_package/tests/markers.ts new file mode 100644 index 000000000..e9ec5c36e --- /dev/null +++ b/nodejs_package/tests/markers.ts @@ -0,0 +1,23 @@ +import {BoardIds, BoardShim} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const board = new BoardShim (BoardIds.SYNTHETIC_BOARD, {}); + board.prepareSession(); + board.startStream(); + await sleep (1000); + board.insertMarker(1); + await sleep (1000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession(); + console.info('Data'); + console.info(data); +} + +runExample (); diff --git a/nodejs_package/tests/package.json b/nodejs_package/tests/package.json new file mode 100644 index 000000000..3697e0cf5 --- /dev/null +++ b/nodejs_package/tests/package.json @@ -0,0 +1,29 @@ +{ + "name": "tests", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "markers": "ts-node markers.ts", + "ica": "ts-node ica.ts", + "brainflow_get_data": "ts-node brainflow_get_data.ts", + "signal_filtering": "ts-node signal_filtering.ts", + "serialization": "ts-node serialization.ts", + "downsampling": "ts-node downsampling.ts", + "transforms": "ts-node transforms.ts", + "denoising": "ts-node denoising.ts", + "bandpower": "ts-node bandpower.ts", + "bandpower_all": "ts-node bandpower_all.ts", + "eeg_metrics": "ts-node eeg_metrics.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.6.0", + "typescript": "^5.2.2" + }, + "dependencies": { + "brainflow": "file:.." + } +} diff --git a/nodejs_package/tests/serialization.ts b/nodejs_package/tests/serialization.ts new file mode 100644 index 000000000..e147d738d --- /dev/null +++ b/nodejs_package/tests/serialization.ts @@ -0,0 +1,26 @@ +import {BoardIds, BoardShim, DataFilter} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const board = new BoardShim (BoardIds.SYNTHETIC_BOARD, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getCurrentBoardData(10); + board.releaseSession() + console.info('Data'); + console.info(data); + DataFilter.writeFile(data, 'test.csv', 'w'); + const dataRestored = DataFilter.readFile('test.csv'); + console.info('Data restored'); + console.info(dataRestored); + DataFilter.writeFile(dataRestored, 'test2.csv', 'w'); +} + +runExample (); diff --git a/nodejs_package/tests/signal_filtering.ts b/nodejs_package/tests/signal_filtering.ts new file mode 100644 index 000000000..a1263d535 --- /dev/null +++ b/nodejs_package/tests/signal_filtering.ts @@ -0,0 +1,32 @@ +import {BoardIds, BoardShim, DataFilter, FilterTypes} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getBoardData(); + board.releaseSession() + console.info('Data'); + console.info(data); + const eegChannels = BoardShim.getEegChannels(boardId); + const samplingRate = BoardShim.getSamplingRate(boardId); + DataFilter.performBandPass( + data[eegChannels[0]], samplingRate, 3.0, 20.0, 2, FilterTypes.BUTTERWORTH_ZERO_PHASE, 0.0); + DataFilter.performBandStop( + data[eegChannels[0]], samplingRate, 48.0, 52.0, 2, FilterTypes.BUTTERWORTH_ZERO_PHASE, 0.0); + DataFilter.performLowPass( + data[eegChannels[0]], samplingRate, 48.0, 2, FilterTypes.BUTTERWORTH_ZERO_PHASE, 0.0); + DataFilter.performHighPass( + data[eegChannels[0]], samplingRate, 3.0, 2, FilterTypes.BUTTERWORTH_ZERO_PHASE, 0.0); +} + +runExample (); diff --git a/nodejs_package/tests/transforms.ts b/nodejs_package/tests/transforms.ts new file mode 100644 index 000000000..9d8fa2021 --- /dev/null +++ b/nodejs_package/tests/transforms.ts @@ -0,0 +1,39 @@ +import { + BoardIds, + BoardShim, + DataFilter, + WaveletExtensionTypes, + WaveletTypes, + WindowOperations +} from 'brainflow'; + +function sleep (ms: number) +{ + return new Promise ((resolve) => { setTimeout (resolve, ms); }); +} + +async function runExample (): Promise +{ + const boardId = BoardIds.SYNTHETIC_BOARD; + const board = new BoardShim (boardId, {}); + board.prepareSession(); + board.startStream(); + await sleep (3000); + board.stopStream(); + const data = board.getCurrentBoardData(64); + board.releaseSession() + const eegChannels = BoardShim.getEegChannels(boardId); + const oldData = data[eegChannels[0]]; + console.info(oldData); + const fftData = DataFilter.performFft(oldData, WindowOperations.NO_WINDOW); + console.info(fftData); + const newData = DataFilter.performIfft(fftData); + console.info(newData); + const waveletData = DataFilter.performWaveletTransform( + newData, WaveletTypes.DB2, 2, WaveletExtensionTypes.SYMMETRIC); + const restoredData = DataFilter.performInverseWaveletTransform( + waveletData, newData.length, WaveletTypes.DB2, 2, WaveletExtensionTypes.SYMMETRIC); + console.info(restoredData); +} + +runExample (); diff --git a/nodejs_package/tests/tsconfig.json b/nodejs_package/tests/tsconfig.json new file mode 100644 index 000000000..6256fe52e --- /dev/null +++ b/nodejs_package/tests/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["es6"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "src", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "build", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/nodejs_package/tsconfig.json b/nodejs_package/tsconfig.json new file mode 100644 index 000000000..81d2e1a64 --- /dev/null +++ b/nodejs_package/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "commonjs", + "lib": ["es5", "es6", "es2015", "es2016", "es2017", "es2018", "esnext"], + "declaration": true, + "sourceMap": true, + "outDir": "./dist", + "removeComments": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", + "rootDirs": ["./", "brainflow"], + "typeRoots": ["./types", "./@types", "node_modules/@types"], + "types": ["node", "jest"], + "esModuleInterop": true, + "preserveConstEnums": true, + "forceConsistentCasingInFileNames": true, + "incremental": true + }, + "include": ["brainflow"], + "exclude": ["node_modules", "tests"] +} diff --git a/nodejs_package/yarn.lock b/nodejs_package/yarn.lock new file mode 100644 index 000000000..0235b06c9 --- /dev/null +++ b/nodejs_package/yarn.lock @@ -0,0 +1,3643 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": + version "7.22.9" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz" + integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.8" + "@babel/types" "^7.22.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + +"@babel/generator@^7.22.7", "@babel/generator@^7.22.9", "@babel/generator@^7.7.2": + version "7.22.9" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz" + integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.22.9": + version "7.22.9" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz" + integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.5", "@babel/template@^7.3.3": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": + version "7.22.8" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.3.3": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.5.0": + version "4.5.1" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + +"@eslint/eslintrc@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz" + integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.44.0": + version "8.44.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz" + integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw== + +"@humanwhocodes/config-array@^0.11.10": + version "0.11.10" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz" + integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.6.1.tgz" + integrity sha512-Aj772AYgwTSr5w8qnyoJ0eDYvN6bMsH3ORH1ivMotrInHLKdUz6BDlaEXHdM6kODaBIkNIyQGzsMvRdOv7VG7Q== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.6.1" + jest-util "^29.6.1" + slash "^3.0.0" + +"@jest/core@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.6.1.tgz" + integrity sha512-CcowHypRSm5oYQ1obz1wfvkjZZ2qoQlrKKvlfPwh5jUXVU12TWr2qMeH8chLMuTFzHh5a1g2yaqlqDICbr+ukQ== + dependencies: + "@jest/console" "^29.6.1" + "@jest/reporters" "^29.6.1" + "@jest/test-result" "^29.6.1" + "@jest/transform" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.6.1" + jest-haste-map "^29.6.1" + jest-message-util "^29.6.1" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.1" + jest-resolve-dependencies "^29.6.1" + jest-runner "^29.6.1" + jest-runtime "^29.6.1" + jest-snapshot "^29.6.1" + jest-util "^29.6.1" + jest-validate "^29.6.1" + jest-watcher "^29.6.1" + micromatch "^4.0.4" + pretty-format "^29.6.1" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.6.1.tgz" + integrity sha512-RMMXx4ws+Gbvw3DfLSuo2cfQlK7IwGbpuEWXCqyYDcqYTI+9Ju3a5hDnXaxjNsa6uKh9PQF2v+qg+RLe63tz5A== + dependencies: + "@jest/fake-timers" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.1" + +"@jest/expect-utils@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.1.tgz" + integrity sha512-o319vIf5pEMx0LmzSxxkYYxo4wrRLKHq9dP1yJU7FoPTB0LfAKSz8SWD6D/6U3v/O52t9cF5t+MeJiRsfk7zMw== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.6.1.tgz" + integrity sha512-N5xlPrAYaRNyFgVf2s9Uyyvr795jnB6rObuPx4QFvNJz8aAjpZUDfO4bh5G/xuplMID8PrnuF1+SfSyDxhsgYg== + dependencies: + expect "^29.6.1" + jest-snapshot "^29.6.1" + +"@jest/fake-timers@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.1.tgz" + integrity sha512-RdgHgbXyosCDMVYmj7lLpUwXA4c69vcNzhrt69dJJdf8azUrpRh3ckFCaTPNjsEeRi27Cig0oKDGxy5j7hOgHg== + dependencies: + "@jest/types" "^29.6.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.6.1" + jest-mock "^29.6.1" + jest-util "^29.6.1" + +"@jest/globals@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.6.1.tgz" + integrity sha512-2VjpaGy78JY9n9370H8zGRCFbYVWwjY6RdDMhoJHa1sYfwe6XM/azGN0SjY8kk7BOZApIejQ1BFPyH7FPG0w3A== + dependencies: + "@jest/environment" "^29.6.1" + "@jest/expect" "^29.6.1" + "@jest/types" "^29.6.1" + jest-mock "^29.6.1" + +"@jest/reporters@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.1.tgz" + integrity sha512-9zuaI9QKr9JnoZtFQlw4GREQbxgmNYXU6QuWtmuODvk5nvPUeBYapVR/VYMyi2WSx3jXTLJTJji8rN6+Cm4+FA== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.6.1" + "@jest/test-result" "^29.6.1" + "@jest/transform" "^29.6.1" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.6.1" + jest-util "^29.6.1" + jest-worker "^29.6.1" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.0": + version "29.6.0" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.0.tgz" + integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.1.tgz" + integrity sha512-Ynr13ZRcpX6INak0TPUukU8GWRfm/vAytE3JbJNGAvINySWYdfE7dGZMbk36oVuK4CigpbhMn8eg1dixZ7ZJOw== + dependencies: + "@jest/console" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.1.tgz" + integrity sha512-oBkC36PCDf/wb6dWeQIhaviU0l5u6VCsXa119yqdUosYAt7/FbQU2M2UoziO3igj/HBDEgp57ONQ3fm0v9uyyg== + dependencies: + "@jest/test-result" "^29.6.1" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.1" + slash "^3.0.0" + +"@jest/transform@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.6.1.tgz" + integrity sha512-URnTneIU3ZjRSaf906cvf6Hpox3hIeJXRnz3VDSw5/X93gR8ycdfSIEy19FlVx8NFmpN7fe3Gb1xF+NjXaQLWg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.1" + jest-regex-util "^29.4.3" + jest-util "^29.6.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.0.0", "@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.1.tgz" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== + dependencies: + "@jest/schemas" "^29.6.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/utils@^2.3.1": + version "2.4.2" + resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@types/babel__core@^7.1.14": + version "7.20.1" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz" + integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.1" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz" + integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@29.5.3": + version "29.5.3" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.3.tgz" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/lodash@4.14.195": + version "4.14.195" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz" + integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== + +"@types/node@*", "@types/node@20.4.2": + version "20.4.2" + resolved "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz" + integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw== + +"@types/prettier@^2.1.5": + version "2.7.3" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.50.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz" + integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/type-utils" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.50.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz" + integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== + dependencies: + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + +"@typescript-eslint/type-utils@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz" + integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== + dependencies: + "@typescript-eslint/typescript-estree" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz" + integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +babel-jest@^29.0.0, babel-jest@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.1.tgz" + integrity sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A== + dependencies: + "@jest/transform" "^29.6.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big-integer@^1.6.44: + version "1.6.51" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.21.9, "browserslist@>= 4.21.0": + version "4.21.9" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz" + integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== + dependencies: + caniuse-lite "^1.0.30001503" + electron-to-chromium "^1.4.431" + node-releases "^2.0.12" + update-browserslist-db "^1.0.11" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001503: + version "1.0.30001517" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz" + integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.6.0: + version "1.9.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +electron-to-chromium@^1.4.431: + version "1.4.465" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.465.tgz" + integrity sha512-XQcuHvEJRMU97UJ75e170mgcITZoz0lIyiaVjk6R+NMTJ8KBIvUHYd1779swgOppUlzxR+JsLpq59PumaXS1jQ== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.22.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz" + integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.1" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.1" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.0" + safe-array-concat "^1.0.0" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.10" + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@8.8.0: + version "8.8.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-config-standard-with-typescript@36.1.0: + version "36.1.0" + resolved "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-36.1.0.tgz" + integrity sha512-Gpk+7Q3EHqIzTnqYs/LpfOwVb8+kocvlFLYhBdCmUy+EUpsC7067PaHhGSp8P4N+lC2KNGBZ7e2tiGyoRNSVHA== + dependencies: + "@typescript-eslint/parser" "^5.50.0" + eslint-config-standard "17.1.0" + +eslint-config-standard@17.1.0: + version "17.1.0" + resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== + +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== + dependencies: + debug "^3.2.7" + is-core-module "^2.11.0" + resolve "^1.22.1" + +eslint-module-utils@^2.7.4: + version "2.8.0" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-es-x@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.1.0.tgz" + integrity sha512-AhiaF31syh4CCQ+C5ccJA0VG6+kJK8+5mXKKE7Qs1xcPRg02CDPOj3mWlQxuWS/AYtg7kxrDNgW9YW3vc0Q+Mw== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.5.0" + +eslint-plugin-import@^2.25.2: + version "2.27.5" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" + has "^1.0.3" + is-core-module "^2.11.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" + tsconfig-paths "^3.14.1" + +"eslint-plugin-n@^15.0.0 || ^16.0.0 ": + version "16.0.1" + resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.1.tgz" + integrity sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.1.0" + ignore "^5.2.4" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" + +eslint-plugin-prettier@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz" + integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" + +eslint-plugin-promise@^6.0.0, eslint-plugin-promise@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz" + integrity sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw== + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.0: + version "7.2.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz" + integrity sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.0.1, eslint@>=7.0.0, eslint@>=8, eslint@>=8.0.0: + version "8.45.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz" + integrity sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.1.0" + "@eslint/js" "8.44.0" + "@humanwhocodes/config-array" "^0.11.10" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.6.0" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0: + version "9.6.1" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execa@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/expect/-/expect-29.6.1.tgz" + integrity sha512-XEdDLonERCU1n9uR56/Stx9OqojaLAQtZf9PrCHH9Hl8YXiEIka3H4NXJ3NOIBmQJTg7+j7buh34PMHfJujc8g== + dependencies: + "@jest/expect-utils" "^29.6.1" + "@types/node" "*" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.1" + jest-message-util "^29.6.1" + jest-util "^29.6.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.2.9, fast-glob@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz" + integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2, functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.12.1: + version "2.12.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.1.tgz" + integrity sha512-tPbYLEiBU4MYAL2XoZme/bgfUeotpDBd81lgHLCbDZZFaGmECk0b+/xejPFtmiBP87GgP/y4jplcRpbH+fgCzQ== + dependencies: + "@jest/environment" "^29.6.1" + "@jest/expect" "^29.6.1" + "@jest/test-result" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.6.1" + jest-matcher-utils "^29.6.1" + jest-message-util "^29.6.1" + jest-runtime "^29.6.1" + jest-snapshot "^29.6.1" + jest-util "^29.6.1" + p-limit "^3.1.0" + pretty-format "^29.6.1" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.1.tgz" + integrity sha512-607dSgTA4ODIN6go9w6xY3EYkyPFGicx51a69H7yfvt7lN53xNswEVLovq+E77VsTRi5fWprLH0yl4DJgE8Ing== + dependencies: + "@jest/core" "^29.6.1" + "@jest/test-result" "^29.6.1" + "@jest/types" "^29.6.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.6.1" + jest-util "^29.6.1" + jest-validate "^29.6.1" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.6.1.tgz" + integrity sha512-XdjYV2fy2xYixUiV2Wc54t3Z4oxYPAELUzWnV6+mcbq0rh742X2p52pii5A3oeRzYjLnQxCsZmp0qpI6klE2cQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.6.1" + "@jest/types" "^29.6.1" + babel-jest "^29.6.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.6.1" + jest-environment-node "^29.6.1" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.1" + jest-runner "^29.6.1" + jest-util "^29.6.1" + jest-validate "^29.6.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.6.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.1.tgz" + integrity sha512-FsNCvinvl8oVxpNLttNQX7FAq7vR+gMDGj90tiP7siWw1UdakWUGqrylpsYrpvj908IYckm5Y0Q7azNAozU1Kg== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.6.1" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.6.1.tgz" + integrity sha512-n5eoj5eiTHpKQCAVcNTT7DRqeUmJ01hsAL0Q1SMiBHcBcvTKDELixQOGMCpqhbIuTcfC4kMfSnpmDqRgRJcLNQ== + dependencies: + "@jest/types" "^29.6.1" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.6.1" + pretty-format "^29.6.1" + +jest-environment-node@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.1.tgz" + integrity sha512-ZNIfAiE+foBog24W+2caIldl4Irh8Lx1PUhg/GZ0odM1d/h2qORAsejiFc7zb+SEmYPn1yDZzEDSU5PmDkmVLQ== + dependencies: + "@jest/environment" "^29.6.1" + "@jest/fake-timers" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.1" + jest-util "^29.6.1" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.1.tgz" + integrity sha512-0m7f9PZXxOCk1gRACiVgX85knUKPKLPg4oRCjLoqIm9brTHXaorMA0JpmtmVkQiT8nmXyIVoZd/nnH1cfC33ig== + dependencies: + "@jest/types" "^29.6.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.6.1" + jest-worker "^29.6.1" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.1.tgz" + integrity sha512-OrxMNyZirpOEwkF3UHnIkAiZbtkBWiye+hhBweCHkVbCgyEy71Mwbb5zgeTNYWJBi1qgDVfPC1IwO9dVEeTLwQ== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.6.1" + +jest-matcher-utils@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.1.tgz" + integrity sha512-SLaztw9d2mfQQKHmJXKM0HCbl2PPVld/t9Xa6P9sgiExijviSp7TnZZpw2Fpt+OI3nwUO/slJbOfzfUMKKC5QA== + dependencies: + chalk "^4.0.0" + jest-diff "^29.6.1" + jest-get-type "^29.4.3" + pretty-format "^29.6.1" + +jest-message-util@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.1.tgz" + integrity sha512-KoAW2zAmNSd3Gk88uJ56qXUWbFk787QKmjjJVOjtGFmmGSZgDBrlIL4AfQw1xyMYPNVD7dNInfIbur9B2rd/wQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.6.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.1.tgz" + integrity sha512-brovyV9HBkjXAEdRooaTQK42n8usKoSRR3gihzUpYeV/vwqgSoNfrksO7UfSACnPmxasO/8TmHM3w9Hp3G1dgw== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-util "^29.6.1" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.1.tgz" + integrity sha512-BbFvxLXtcldaFOhNMXmHRWx1nXQO5LoXiKSGQcA1LxxirYceZT6ch8KTE1bK3X31TNG/JbkI7OkS/ABexVahiw== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.6.1" + +jest-resolve@*, jest-resolve@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.1.tgz" + integrity sha512-AeRkyS8g37UyJiP9w3mmI/VXU/q8l/IH52vj/cDAyScDcemRbSBhfX/NMYIGilQgSVwsjxrCHf3XJu4f+lxCMg== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.1" + jest-pnp-resolver "^1.2.2" + jest-util "^29.6.1" + jest-validate "^29.6.1" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.1.tgz" + integrity sha512-tw0wb2Q9yhjAQ2w8rHRDxteryyIck7gIzQE4Reu3JuOBpGp96xWgF0nY8MDdejzrLCZKDcp8JlZrBN/EtkQvPQ== + dependencies: + "@jest/console" "^29.6.1" + "@jest/environment" "^29.6.1" + "@jest/test-result" "^29.6.1" + "@jest/transform" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.6.1" + jest-haste-map "^29.6.1" + jest-leak-detector "^29.6.1" + jest-message-util "^29.6.1" + jest-resolve "^29.6.1" + jest-runtime "^29.6.1" + jest-util "^29.6.1" + jest-watcher "^29.6.1" + jest-worker "^29.6.1" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.1.tgz" + integrity sha512-D6/AYOA+Lhs5e5il8+5pSLemjtJezUr+8zx+Sn8xlmOux3XOqx4d8l/2udBea8CRPqqrzhsKUsN/gBDE/IcaPQ== + dependencies: + "@jest/environment" "^29.6.1" + "@jest/fake-timers" "^29.6.1" + "@jest/globals" "^29.6.1" + "@jest/source-map" "^29.6.0" + "@jest/test-result" "^29.6.1" + "@jest/transform" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.1" + jest-message-util "^29.6.1" + jest-mock "^29.6.1" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.1" + jest-snapshot "^29.6.1" + jest-util "^29.6.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.1.tgz" + integrity sha512-G4UQE1QQ6OaCgfY+A0uR1W2AY0tGXUPQpoUClhWHq1Xdnx1H6JOrC2nH5lqnOEqaDgbHFgIwZ7bNq24HpB180A== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.6.1" + "@jest/transform" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.6.1" + graceful-fs "^4.2.9" + jest-diff "^29.6.1" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.1" + jest-message-util "^29.6.1" + jest-util "^29.6.1" + natural-compare "^1.4.0" + pretty-format "^29.6.1" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.6.1.tgz" + integrity sha512-NRFCcjc+/uO3ijUVyNOQJluf8PtGCe/W6cix36+M3cTFgiYqFOOW5MgN4JOOcvbUhcKTYVd1CvHz/LWi8d16Mg== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.1.tgz" + integrity sha512-r3Ds69/0KCN4vx4sYAbGL1EVpZ7MSS0vLmd3gV78O+NAx3PDQQukRU5hNHPXlyqCgFY8XUk7EuTMLugh0KzahA== + dependencies: + "@jest/types" "^29.6.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.6.1" + +jest-watcher@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.1.tgz" + integrity sha512-d4wpjWTS7HEZPaaj8m36QiaP856JthRZkrgcIY/7ISoUWPIillrXM23WPboZVLbiwZBt4/qn2Jke84Sla6JhFA== + dependencies: + "@jest/test-result" "^29.6.1" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.6.1" + string-length "^4.0.1" + +jest-worker@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.1.tgz" + integrity sha512-U+Wrbca7S8ZAxAe9L6nb6g8kPdia5hj32Puu5iOqBCMTMWFHXuK6dOV2IFrpedbTV8fjMFLdWNttQTBL6u2MRA== + dependencies: + "@types/node" "*" + jest-util "^29.6.1" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.0.0, jest@29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/jest/-/jest-29.6.1.tgz" + integrity sha512-Nirw5B4nn69rVUZtemCQhwxOBhm0nsp3hmtF4rzCeWD7BkjAXRIji7xWQfnTNbz9g0aVsBX6aZK3n+23LM6uDw== + dependencies: + "@jest/core" "^29.6.1" + "@jest/types" "^29.6.1" + import-local "^3.0.2" + jest-cli "^29.6.1" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +koffi@2.5.7: + version "2.5.7" + resolved "https://registry.npmjs.org/koffi/-/koffi-2.5.7.tgz" + integrity sha512-BQfUHG6hXJ8Wpd0kwl1n0jx3VPYN9F6yFCWEEUdyrBvb7YJBt5e762y5nQpbORkq5Tj96ZzriGIK9VCgY1qmGg== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@^2.1.1, ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.12: + version "2.0.13" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + +object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +open@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/open/-/open-9.1.0.tgz" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^2.2.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@>=3.0.0, prettier@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz" + integrity sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g== + +pretty-format@^29.0.0, pretty-format@^29.6.1: + version "29.6.1" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.1.tgz" + integrity sha512-7jRj+yXO0W7e4/tSJKoR7HRIHLPPjtNaUGG2xxKQnGvPNRkgWcQ0AZX6P4KBRJN4FcTBWb3sa7DVUJmocYuoog== + dependencies: + "@jest/schemas" "^29.6.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +regexp.prototype.flags@^1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + functions-have-names "^1.2.3" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.2: + version "1.22.2" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz" + integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +semver@^6.0.0: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^6.3.0: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.0.0, semver@^7.3.7, semver@^7.5.3: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +synckit@^0.8.5: + version "0.8.5" + resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz" + integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + dependencies: + "@pkgr/utils" "^2.3.1" + tslib "^2.5.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-jest@29.1.1: + version "29.1.1" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +tsconfig-paths@^3.14.1: + version "3.14.2" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.5.0, tslib@^2.6.0: + version "2.6.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typescript@*, typescript@^5.1.6, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", "typescript@>=4.3 <6": + version "5.1.6" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.10, which-typed-array@^1.1.11: + version "1.1.11" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake index 0a6632234..7b9e37a07 100644 --- a/src/board_controller/build.cmake +++ b/src/board_controller/build.cmake @@ -170,6 +170,7 @@ endif (USE_LIBFTDI) if (MSVC) add_custom_command (TARGET ${BOARD_CONTROLLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BOARD_CONTROLLER_COMPILED_NAME}" @@ -187,6 +188,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${BOARD_CONTROLLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BOARD_CONTROLLER_COMPILED_NAME}" diff --git a/src/board_controller/muse/muse_bglib/build.cmake b/src/board_controller/muse/muse_bglib/build.cmake index d04a3c0cb..f72d8587a 100644 --- a/src/board_controller/muse/muse_bglib/build.cmake +++ b/src/board_controller/muse/muse_bglib/build.cmake @@ -52,6 +52,7 @@ set_target_properties (${MUSE_BLED_LIB} if (MSVC) add_custom_command (TARGET ${MUSE_BLED_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${MUSE_BLED_LIB_NAME}" @@ -61,6 +62,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${MUSE_BLED_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${MUSE_BLED_LIB_NAME}" diff --git a/src/board_controller/neuromd/brainbit_bglib/build.cmake b/src/board_controller/neuromd/brainbit_bglib/build.cmake index 8b3f01d41..f4f1ffe93 100644 --- a/src/board_controller/neuromd/brainbit_bglib/build.cmake +++ b/src/board_controller/neuromd/brainbit_bglib/build.cmake @@ -48,6 +48,7 @@ set_target_properties (${BRAINBIT_BLED_LIB} if (MSVC) add_custom_command (TARGET ${BRAINBIT_BLED_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" @@ -57,6 +58,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${BRAINBIT_BLED_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BRAINBIT_BLED_LIB_NAME}" diff --git a/src/board_controller/openbci/ganglion_bglib/build.cmake b/src/board_controller/openbci/ganglion_bglib/build.cmake index 9384aba40..f72af74c9 100644 --- a/src/board_controller/openbci/ganglion_bglib/build.cmake +++ b/src/board_controller/openbci/ganglion_bglib/build.cmake @@ -46,6 +46,7 @@ set_target_properties (${GANGLION_LIB} if (MSVC) add_custom_command (TARGET ${GANGLION_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${GANGLION_LIB_NAME}" @@ -55,6 +56,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${GANGLION_LIB} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${GANGLION_LIB_NAME}" diff --git a/src/board_controller/synthetic_board.cpp b/src/board_controller/synthetic_board.cpp index 22a34b06c..a5f6783ed 100644 --- a/src/board_controller/synthetic_board.cpp +++ b/src/board_controller/synthetic_board.cpp @@ -255,5 +255,6 @@ void SyntheticBoard::read_thread () int SyntheticBoard::config_board (std::string config, std::string &response) { + response = "Config:" + config; return (int)BrainFlowExitCodes::STATUS_OK; } diff --git a/src/data_handler/build.cmake b/src/data_handler/build.cmake index f53030aae..a9be27a29 100644 --- a/src/data_handler/build.cmake +++ b/src/data_handler/build.cmake @@ -77,6 +77,7 @@ endif (ANDROID) if (MSVC) add_custom_command (TARGET ${DATA_HANDLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${DATA_HANDLER_COMPILED_NAME}" @@ -91,6 +92,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${DATA_HANDLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${DATA_HANDLER_COMPILED_NAME}" diff --git a/src/ml/build.cmake b/src/ml/build.cmake index f6c9ba5da..120eaf4c3 100644 --- a/src/ml/build.cmake +++ b/src/ml/build.cmake @@ -78,6 +78,7 @@ endif (ANDROID) if (MSVC) add_custom_command (TARGET ${ML_MODULE_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${ML_MODULE_COMPILED_NAME}" @@ -93,6 +94,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${ML_MODULE_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${ML_MODULE_COMPILED_NAME}" diff --git a/src/utils/bluetooth/build.cmake b/src/utils/bluetooth/build.cmake index 724103015..43df2aa98 100644 --- a/src/utils/bluetooth/build.cmake +++ b/src/utils/bluetooth/build.cmake @@ -69,6 +69,7 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/matlab_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/rust_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" ) endif (MSVC) if (UNIX AND NOT ANDROID) @@ -79,6 +80,7 @@ if (UNIX AND NOT ANDROID) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/matlab_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/rust_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" ) endif (UNIX AND NOT ANDROID) diff --git a/third_party/SimpleBLE/simpleble/CMakeLists.txt b/third_party/SimpleBLE/simpleble/CMakeLists.txt index 75ff61522..ad8a70fca 100644 --- a/third_party/SimpleBLE/simpleble/CMakeLists.txt +++ b/third_party/SimpleBLE/simpleble/CMakeLists.txt @@ -300,6 +300,7 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/$/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../matlab_package/brainflow/lib/${FILE_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/$/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../julia_package/brainflow/lib/${FILE_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/$/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../rust_package/brainflow/lib/${FILE_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/$/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../nodejs_package/brainflow/lib/${FILE_NAME}" ) endif (MSVC) if (UNIX AND NOT ANDROID) @@ -310,6 +311,7 @@ if (UNIX AND NOT ANDROID) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../csharp_package/brainflow/brainflow/${FILE_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../matlab_package/brainflow/lib/${FILE_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../rust_package/brainflow/lib/${FILE_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../../compiled/${FILE_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../nodejs_package/brainflow/lib/${FILE_NAME}" ) endif (UNIX AND NOT ANDROID) diff --git a/third_party/gForceSDKCXX/build.cmake b/third_party/gForceSDKCXX/build.cmake index b4e783298..9788cdc5b 100644 --- a/third_party/gForceSDKCXX/build.cmake +++ b/third_party/gForceSDKCXX/build.cmake @@ -45,11 +45,15 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GFORCE_SDK_WRAPPER_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${GFORCE_SDK_WRAPPER_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GFORCE_SDK_WRAPPER_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${GFORCE_SDK_WRAPPER_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GFORCE_SDK_WRAPPER_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${GFORCE_SDK_WRAPPER_NAME}.dll" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GFORCE_SDK_WRAPPER_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/src/main/resources/${GFORCE_SDK_WRAPPER_NAME}.dll" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/$/${GFORCE_SDK_WRAPPER_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/rust_package/brainflow/lib/${GFORCE_SDK_WRAPPER_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/matlab_package/brainflow/lib/${GFORCE_SDK_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${GFORCE_SDK_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/${GFORCE_SDK_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${GFORCE_SDK_NAME}.dll" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${GFORCE_SDK_NAME}.dll" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${GFORCE_SDK_NAME}.dll" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/lib/${GFORCE_SDK_NAME}.dll" "${CMAKE_CURRENT_SOURCE_DIR}/rust_package/brainflow/lib/${GFORCE_SDK_NAME}.dll" ) endif (MSVC) From 7158c67d3b5075603bd17d4d195ee7b2b755ea69 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Thu, 14 Sep 2023 12:28:27 +0200 Subject: [PATCH 07/16] bump julia version Signed-off-by: Andrey Parfenov --- julia_package/brainflow/Artifacts.toml | 6 +++--- julia_package/brainflow/Project.toml | 2 +- julia_package/brainflow/src/brainflow_url.jl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/julia_package/brainflow/Artifacts.toml b/julia_package/brainflow/Artifacts.toml index e286bdf3d..2a9334731 100644 --- a/julia_package/brainflow/Artifacts.toml +++ b/julia_package/brainflow/Artifacts.toml @@ -1,7 +1,7 @@ [brainflow] -git-tree-sha1 = "f4995399d29b7540a4735be83e73c96a08d52298" +git-tree-sha1 = "112de0c1e1b3d2b2ad897da59e49165f74b0ba61" lazy = true [[brainflow.download]] - sha256 = "8ab1670438ac7dcf365c8ef1ef7858c183d9ae75511cc51051e9319968a187bc" - url = "https://github.com/brainflow-dev/brainflow/releases/download/5.9.0/compiled_libs.tar" + sha256 = "45e386ebed7eb0215b87fd9a4ac6c7e8fbe830c31651dd05717532ae2bf3b982" + url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.0/compiled_libs.tar" diff --git a/julia_package/brainflow/Project.toml b/julia_package/brainflow/Project.toml index ea0a1ac66..969b90e42 100644 --- a/julia_package/brainflow/Project.toml +++ b/julia_package/brainflow/Project.toml @@ -1,7 +1,7 @@ name = "BrainFlow" uuid = "abd5acf9-0fc9-4730-984d-e27a37823580" authors = ["Andrey1994 "] -version = "5.9.0" +version = "5.10.0" [deps] JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" diff --git a/julia_package/brainflow/src/brainflow_url.jl b/julia_package/brainflow/src/brainflow_url.jl index 3fcc5f128..8cc8dea87 100644 --- a/julia_package/brainflow/src/brainflow_url.jl +++ b/julia_package/brainflow/src/brainflow_url.jl @@ -1,5 +1,5 @@ # TODO: automatically generate by brainflow CICD function brainflow_url() - url = "https://github.com/brainflow-dev/brainflow/releases/download/5.9.0/compiled_libs.tar" + url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.0/compiled_libs.tar" return url end \ No newline at end of file From 5b3a118495df034b74218fdf6831c8af55aa689c Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Thu, 14 Sep 2023 14:04:07 +0300 Subject: [PATCH 08/16] Update BuildBrainFlow.rst --- docs/BuildBrainFlow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/BuildBrainFlow.rst b/docs/BuildBrainFlow.rst index 578cbc924..30282c3f5 100644 --- a/docs/BuildBrainFlow.rst +++ b/docs/BuildBrainFlow.rst @@ -135,7 +135,7 @@ Typescript If you want to install it from source files or build unreleased version from Github, you should first compile the core module (:ref:`compilation-label`). Then run :: cd nodejs_package - npm install --force + npm install Rust From bee49d3e1111caf633a315b28cfb3476c104a4a2 Mon Sep 17 00:00:00 2001 From: Philip Pitts <84428015+philippitts@users.noreply.github.com> Date: Wed, 20 Sep 2023 01:07:39 -0400 Subject: [PATCH 09/16] Support Ganglion v3 detection on MacOS native BLE (#675) --- src/board_controller/ble_lib_board.cpp | 23 +++++++++++++++++++ src/board_controller/inc/ble_lib_board.h | 3 +++ .../openbci/ganglion_native.cpp | 19 +++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/board_controller/ble_lib_board.cpp b/src/board_controller/ble_lib_board.cpp index 145e82352..be231b073 100644 --- a/src/board_controller/ble_lib_board.cpp +++ b/src/board_controller/ble_lib_board.cpp @@ -610,6 +610,29 @@ simpleble_err_t BLELibBoard::simpleble_peripheral_manufacturer_data_get ( return func (handle, index, manufacturer_data); } +simpleble_err_t BLELibBoard::simpleble_peripheral_read (simpleble_peripheral_t handle, + simpleble_uuid_t service, simpleble_uuid_t characteristic, uint8_t **data, size_t *data_length) +{ + std::lock_guard lock (BLELibBoard::mutex); + if (BLELibBoard::dll_loader == NULL) + { + safe_logger (spdlog::level::err, "BLELibBoard::dll_loader is not initialized"); + return SIMPLEBLE_FAILURE; + } + simpleble_err_t (*func) (simpleble_peripheral_t, simpleble_uuid_t, simpleble_uuid_t, uint8_t **, + size_t *) = (simpleble_err_t (*) (simpleble_peripheral_t, simpleble_uuid_t, + simpleble_uuid_t, uint8_t **, + size_t *))BLELibBoard::dll_loader->get_address ("simpleble_peripheral_read"); + if (func == NULL) + { + safe_logger ( + spdlog::level::err, "failed to get function address for simpleble_peripheral_read"); + return SIMPLEBLE_FAILURE; + } + + return func (handle, service, characteristic, data, data_length); +} + simpleble_err_t BLELibBoard::simpleble_peripheral_is_connected ( simpleble_peripheral_t handle, bool *connected) { diff --git a/src/board_controller/inc/ble_lib_board.h b/src/board_controller/inc/ble_lib_board.h index 32cf196ad..b252d47a6 100644 --- a/src/board_controller/inc/ble_lib_board.h +++ b/src/board_controller/inc/ble_lib_board.h @@ -58,6 +58,9 @@ class BLELibBoard : public Board size_t simpleble_peripheral_manufacturer_data_count (simpleble_peripheral_t handle); simpleble_err_t simpleble_peripheral_manufacturer_data_get (simpleble_peripheral_t handle, size_t index, simpleble_manufacturer_data_t *manufacturer_data); + simpleble_err_t simpleble_peripheral_read (simpleble_peripheral_t handle, + simpleble_uuid_t service, simpleble_uuid_t characteristic, uint8_t **data, + size_t *data_length); simpleble_err_t simpleble_peripheral_is_connected ( simpleble_peripheral_t handle, bool *connected); diff --git a/src/board_controller/openbci/ganglion_native.cpp b/src/board_controller/openbci/ganglion_native.cpp index a96d90cf1..986b8b1ee 100644 --- a/src/board_controller/openbci/ganglion_native.cpp +++ b/src/board_controller/openbci/ganglion_native.cpp @@ -8,6 +8,7 @@ #define GANGLION_WRITE_CHAR "2d30c083-f39f-4ce6-923f-3484ea480596" #define GANGLION_NOTIFY_CHAR "2d30c082-f39f-4ce6-923f-3484ea480596" +#define GANGLION_SOFTWARE_REVISION "00002a28-0000-1000-8000-00805f9b34fb" static void ganglion_adapter_1_on_scan_start (simpleble_adapter_t adapter, void *board) @@ -108,7 +109,6 @@ int GanglionNative::prepare_session () lk, params.timeout * sec, [this] { return this->ganglion_peripheral != NULL; })) { safe_logger (spdlog::level::info, "Found GanglionNative device"); - safe_logger (spdlog::level::info, "Detected firmware version {}", firmware); } else { @@ -162,11 +162,21 @@ int GanglionNative::prepare_session () res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; } - safe_logger (spdlog::level::trace, "found servce {}", service.uuid.value); + safe_logger (spdlog::level::trace, "found service {}", service.uuid.value); for (size_t j = 0; j < service.characteristic_count; j++) { - safe_logger (spdlog::level::trace, "found characteristic {}", - service.characteristics[j].uuid.value); + // Read the software revision characteristic to get the firmware version + if (strcmp (service.characteristics[j].uuid.value, GANGLION_SOFTWARE_REVISION) == 0) + { + uint8_t *data; + size_t data_length; + simpleble_peripheral_read (ganglion_peripheral, service.uuid, + service.characteristics[j].uuid, &data, &data_length); + + // Data should be in the form x.x.x stored as ASCII values in the data buffer + firmware = (data[0] == '3') ? 3 : 2; + safe_logger (spdlog::level::info, "Detected firmware version {}", firmware); + } if (strcmp (service.characteristics[j].uuid.value, GANGLION_WRITE_CHAR) == 0) // Write Characteristics @@ -444,7 +454,6 @@ void GanglionNative::adapter_1_on_scan_found ( if (found) { - firmware = strncmp (peripheral_identified, "Ganglion 1.3", 12) == 0 ? 3 : 2; { std::lock_guard lk (m); ganglion_peripheral = peripheral; From 4c21e69678646bfb03bf3e96e45344248e25b9d3 Mon Sep 17 00:00:00 2001 From: myd7349 Date: Sat, 23 Sep 2023 14:13:16 +0800 Subject: [PATCH 10/16] Fix linear detrend (#676) --- src/data_handler/data_handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_handler/data_handler.cpp b/src/data_handler/data_handler.cpp index 45f3631fe..106c614dd 100644 --- a/src/data_handler/data_handler.cpp +++ b/src/data_handler/data_handler.cpp @@ -1207,7 +1207,7 @@ int detrend (double *data, int data_len, int detrend_operation) if (detrend_operation == (int)DetrendOperations::LINEAR) { // use mean and gradient to find a line - double mean_x = data_len / 2.0; + double mean_x = (data_len - 1) / 2.0; double mean_y = 0; for (int i = 0; i < data_len; i++) { From 0756ab3196d9747e8e17c47623f2b2ac253edb52 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Mon, 25 Sep 2023 18:19:56 +0200 Subject: [PATCH 11/16] fixing docs Signed-off-by: Andrey Parfenov --- .readthedocs.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 000000000..4f45e6144 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,35 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + fail_on_warning: false + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file From fe2d98613f53867141e0ea2c1abb738d4402933c Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Thu, 28 Sep 2023 20:05:52 +0200 Subject: [PATCH 12/16] bump julia version Signed-off-by: Andrey Parfenov --- julia_package/brainflow/Artifacts.toml | 6 +++--- julia_package/brainflow/Project.toml | 2 +- julia_package/brainflow/src/brainflow_url.jl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/julia_package/brainflow/Artifacts.toml b/julia_package/brainflow/Artifacts.toml index 2a9334731..77a7246f4 100644 --- a/julia_package/brainflow/Artifacts.toml +++ b/julia_package/brainflow/Artifacts.toml @@ -1,7 +1,7 @@ [brainflow] -git-tree-sha1 = "112de0c1e1b3d2b2ad897da59e49165f74b0ba61" +git-tree-sha1 = "66f67bebce97d56b31229d6ec8e6f5b00fc75bda" lazy = true [[brainflow.download]] - sha256 = "45e386ebed7eb0215b87fd9a4ac6c7e8fbe830c31651dd05717532ae2bf3b982" - url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.0/compiled_libs.tar" + sha256 = "dcfc69d6625b67903fc95d3be27de922c7533baba4971f4ae13539c52675fb05" + url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.1/compiled_libs.tar" diff --git a/julia_package/brainflow/Project.toml b/julia_package/brainflow/Project.toml index 969b90e42..c14d4db6c 100644 --- a/julia_package/brainflow/Project.toml +++ b/julia_package/brainflow/Project.toml @@ -1,7 +1,7 @@ name = "BrainFlow" uuid = "abd5acf9-0fc9-4730-984d-e27a37823580" authors = ["Andrey1994 "] -version = "5.10.0" +version = "5.10.1" [deps] JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" diff --git a/julia_package/brainflow/src/brainflow_url.jl b/julia_package/brainflow/src/brainflow_url.jl index 8cc8dea87..fc0b66cf1 100644 --- a/julia_package/brainflow/src/brainflow_url.jl +++ b/julia_package/brainflow/src/brainflow_url.jl @@ -1,5 +1,5 @@ # TODO: automatically generate by brainflow CICD function brainflow_url() - url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.0/compiled_libs.tar" + url = "https://github.com/brainflow-dev/brainflow/releases/download/5.10.1/compiled_libs.tar" return url end \ No newline at end of file From 963f8435760cb66b1b8de06bd7f5a05bfa7f54a0 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Tue, 3 Oct 2023 19:27:05 +0200 Subject: [PATCH 13/16] fixing gain tracker Signed-off-by: Andrey Parfenov --- src/board_controller/openbci/inc/openbci_gain_tracker.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/board_controller/openbci/inc/openbci_gain_tracker.h b/src/board_controller/openbci/inc/openbci_gain_tracker.h index 40ae153a3..4b153136a 100644 --- a/src/board_controller/openbci/inc/openbci_gain_tracker.h +++ b/src/board_controller/openbci/inc/openbci_gain_tracker.h @@ -224,6 +224,8 @@ class GaleaV4GainTracker : public OpenBCIGainTracker : OpenBCIGainTracker ({4, 4, 4, 4, 4, 4, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}) // to be confirmed { + channel_letters = std::vector {'1', '2', '3', '4', '5', '6', '7', '8', 'Q', 'W', 'E', + 'R', 'T', 'Y', 'U', 'I', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K'}; } virtual int apply_config (std::string config) From 0071b9c50e6b05943b31308cb8d7900dac58af4f Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Tue, 3 Oct 2023 19:52:30 +0200 Subject: [PATCH 14/16] fixing gain tracker Signed-off-by: Andrey Parfenov --- src/board_controller/openbci/inc/openbci_gain_tracker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/board_controller/openbci/inc/openbci_gain_tracker.h b/src/board_controller/openbci/inc/openbci_gain_tracker.h index 4b153136a..69e0a9975 100644 --- a/src/board_controller/openbci/inc/openbci_gain_tracker.h +++ b/src/board_controller/openbci/inc/openbci_gain_tracker.h @@ -225,7 +225,7 @@ class GaleaV4GainTracker : public OpenBCIGainTracker 2, 2}) // to be confirmed { channel_letters = std::vector {'1', '2', '3', '4', '5', '6', '7', '8', 'Q', 'W', 'E', - 'R', 'T', 'Y', 'U', 'I', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K'}; + 'R', 'T', 'Y', 'U', 'I', 'A', 'S', 'D', 'G', 'H', 'J', 'K', 'L'}; } virtual int apply_config (std::string config) From 3caf957dd1dee287f11d5dda5b6a6ccbecc4ce3a Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Mon, 16 Oct 2023 20:05:16 +0200 Subject: [PATCH 15/16] Update BoardShim.m --- matlab_package/brainflow/BoardShim.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matlab_package/brainflow/BoardShim.m b/matlab_package/brainflow/BoardShim.m index 0c1d2772f..288968563 100644 --- a/matlab_package/brainflow/BoardShim.m +++ b/matlab_package/brainflow/BoardShim.m @@ -286,7 +286,7 @@ function log_message(log_level, message) end function rotation_channels = get_rotation_channels(board_id, preset) - % get accel channels for provided board id + % get rotation channels for provided board id task_name = 'get_rotation_channels'; lib_name = BoardShim.load_lib(); num_channels = libpointer('int32Ptr', 0); @@ -491,4 +491,4 @@ function insert_marker(obj, value, preset) end -end \ No newline at end of file +end From 8305c608f6a50d70a2f9e0506a3e57d2fa5daf39 Mon Sep 17 00:00:00 2001 From: Richard Waltman Date: Thu, 26 Oct 2023 14:43:49 -0500 Subject: [PATCH 16/16] Add check for os.arch when unpacking MLModel .dlls on WIndows (#679) * Add check for os.arch when unpacking MLModel .dlls on WIndows --- .../src/main/java/brainflow/MLModel.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/java_package/brainflow/src/main/java/brainflow/MLModel.java b/java_package/brainflow/src/main/java/brainflow/MLModel.java index b947e73b4..dd43212cc 100644 --- a/java_package/brainflow/src/main/java/brainflow/MLModel.java +++ b/java_package/brainflow/src/main/java/brainflow/MLModel.java @@ -43,10 +43,24 @@ private interface DllInterface extends Library if (SystemUtils.IS_OS_WINDOWS) { lib_name = "MLModule.dll"; - JarHelper.unpack_from_jar ("onnxruntime_arm.dll"); - JarHelper.unpack_from_jar ("onnxruntime_arm64.dll"); - JarHelper.unpack_from_jar ("onnxruntime_x64.dll"); - JarHelper.unpack_from_jar ("onnxruntime_x86.dll"); + String arch = System.getProperty ("os.arch"); + switch (arch) { + case "x86": + JarHelper.unpack_from_jar ("onnxruntime_x86.dll"); + break; + case "x86_64": + case "amd64": + JarHelper.unpack_from_jar ("onnxruntime_x64.dll"); + break; + case "arm": + JarHelper.unpack_from_jar ("onnxruntime_arm.dll"); + break; + case "arm64": + JarHelper.unpack_from_jar ("onnxruntime_arm64.dll"); + break; + default: + System.err.println("Unsupported Windows architecture: " + arch); + } } else if (SystemUtils.IS_OS_MAC) { lib_name = "libMLModule.dylib";