diff --git a/.gitattributes b/.gitattributes index 1d51ab9ec9fd246713ecdfec8929f7bed824968e..6df79453d7bb5bd282a6c2d8a824702ba0986765 100644 --- a/.gitattributes +++ b/.gitattributes @@ -86,3 +86,11 @@ python/cactus_needle-3.0.2-py3-none-musllinux_1_2_aarch64.whl filter=lfs diff=lf python/cactus_needle-3.0.2-py3-none-musllinux_1_2_x86_64.whl filter=lfs diff=lfs merge=lfs -text python/cactus_needle-3.0.2-py3-none-win_amd64.whl filter=lfs diff=lfs merge=lfs -text python/cactus_needle-3.0.2-py3-none-win_arm64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-macosx_11_0_arm64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-macosx_11_0_x86_64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-manylinux2014_aarch64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-manylinux2014_x86_64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-musllinux_1_2_aarch64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-musllinux_1_2_x86_64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-win_amd64.whl filter=lfs diff=lfs merge=lfs -text +python/cactus_needle-3.1.0-py3-none-win_arm64.whl filter=lfs diff=lfs merge=lfs -text diff --git a/android-arm64/libneedle.a b/android-arm64/libneedle.a index d46a7de5295a0b89437711a790c492cda2932ebe..3316a3f7fbcbc8a11689ac13b4feaa6402d31d60 100644 --- a/android-arm64/libneedle.a +++ b/android-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8e73952054686f68e4319dcf69ad72a3de57faab73b73d9a67898f2c9d66110 -size 1664680 +oid sha256:16752fb75adea7af89bbc435a97d1cda7e71bc74d04578d551d0d3bbd5f9e633 +size 2128166 diff --git a/android-arm64/needle b/android-arm64/needle index d3e2c2049623353e6e3119036cfb3e41e262aa64..471a772a07621c5b0396a835042523c389918faf 100644 --- a/android-arm64/needle +++ b/android-arm64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:894f7859b92ec7693de721dc60812ce6a4317cdd7f8c31021c4eb1ab27345105 -size 1192864 +oid sha256:4a8f2090c5dc7d21ca52b9d167682d5ccb51f730fa21f4c6a700b320c858a17b +size 1468888 diff --git a/android-arm64/needle.h b/android-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/android-arm64/needle.h +++ b/android-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/android-armv7/libneedle.a b/android-armv7/libneedle.a index 33fc3a6de27bc2f97706c995d0f3b3600b0e2580..191e6308b3995ad8fbb8e8094c842c9345694bf5 100644 --- a/android-armv7/libneedle.a +++ b/android-armv7/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:162d98ef1e9d91db670ccc2f40d0de5a45d4184bf62995f4ae62a9dea52d862c -size 1291188 +oid sha256:8cb5af3c2a7e6ad55a1fe94cb9b6c012b40ae921aae2981594362389872fa7c0 +size 1646250 diff --git a/android-armv7/needle b/android-armv7/needle index f3cef80e6780d5f866b1d3dd715ba2d14a518944..3481f3a08eef94591916ca6c62ccc968253bf9eb 100644 --- a/android-armv7/needle +++ b/android-armv7/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eeafc203dfb3b3f4e51d842df94af85df2cc99c79e5477582da501e05922d3e3 -size 703536 +oid sha256:eab77b1712b5127201d7e9cbb700f03b3645566347be0446c4818002deeab9d3 +size 893692 diff --git a/android-armv7/needle.h b/android-armv7/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/android-armv7/needle.h +++ b/android-armv7/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/android-riscv64/libneedle.a b/android-riscv64/libneedle.a index 3d9e0312d802b8c2f67883555d138cd3f5f7154b..c38bdae872081c72f2cfe5fa0be8dac2d2dbacc2 100644 --- a/android-riscv64/libneedle.a +++ b/android-riscv64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92396186b83ed15dd385d4e2084fdb722f0f4ab434096ae7c3de02bb1055959d -size 3715858 +oid sha256:5580972d83ea6eb466c0989d605935233360564b24f20ef7f671c08e0e8f7482 +size 4634608 diff --git a/android-riscv64/needle b/android-riscv64/needle index 8e6eee238088ca09aa259092b8d6c3558f11415c..aa0609404cf267e1e9ff21c24c5869fde9646979 100644 --- a/android-riscv64/needle +++ b/android-riscv64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78acd7a7b34afdbc33fa8940aecb564eb3701bb0ac27fe26aa73ff727981761f -size 1040256 +oid sha256:846948100f440c014f046c4615a2ff0cc9febeabef0768fda9db5a4e98f7e82f +size 1277992 diff --git a/android-riscv64/needle.h b/android-riscv64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/android-riscv64/needle.h +++ b/android-riscv64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/assets/deploy.svg b/assets/deploy.svg index 01b6159fe6ababc98466ec39e5231f2554fc7009..4ecbc512f60bc19b59512fa21700318a681e1899 100644 --- a/assets/deploy.svg +++ b/assets/deploy.svg @@ -1,8 +1,8 @@ - + One engine per platform folder -each under 1 MB, each loading the same needle3.cact +each loading any .cact you hand it Mac (Apple Silicon) macos-arm64 diff --git a/config.json b/config.json index 42053bb5dbe28ddefa266d90d66babbf40091968..ae7e4365274bf396728f1dc35f3892038f9475ea 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "model_type": "needle", - "engine_version": "3.0.2", + "engine_version": "3.1.0", "architectures": [ "NeedleForToolCalling" ], diff --git a/ios-arm64/libneedle.a b/ios-arm64/libneedle.a index ea835ea1a5715f174c2e7f51da2248bf732d236a..7b64ab487c738017e69166327f6178578b38f207 100644 --- a/ios-arm64/libneedle.a +++ b/ios-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cbacdf197c997b126962bedc8852b970ee73c7367b5f605123d318f04423cc6 -size 1137864 +oid sha256:e507b914d32cfe7dfbc9be8de65dc899451d8cbd38a63b2e47bfddaca73373ac +size 1465680 diff --git a/ios-arm64/needle.h b/ios-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/ios-arm64/needle.h +++ b/ios-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/ios-sim-arm64/libneedle.a b/ios-sim-arm64/libneedle.a index 21de368a20aafc0ba1563f9a088010f595f3c7e6..4aa04f62893ec62dd1d00a9d7156e99c64f559f1 100644 --- a/ios-sim-arm64/libneedle.a +++ b/ios-sim-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a6692dc58b9e4b49d7c1cc0223e3b36dcb7ad4ab613579773939536a3668d66 -size 1155504 +oid sha256:a75a67f98c057cef82977e5e1e3d505b57fed131710a5ae89683ad9d0d74d849 +size 1503120 diff --git a/ios-sim-arm64/needle.h b/ios-sim-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/ios-sim-arm64/needle.h +++ b/ios-sim-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/linux-arm64/libneedle.a b/linux-arm64/libneedle.a index 8b881005d561488ac0d2640b496f9523862478a2..ac5f41bb4d5a806b96f4d0fa8965c1b1ebd9bc8c 100644 --- a/linux-arm64/libneedle.a +++ b/linux-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc94801686922cb2ea2be6822046d1c152e5b3a7e93c773ecbb8cf0f0fab61d3 -size 1540974 +oid sha256:d6e33724cab170f0a25bd943d3a8ed5da925fcb793e9fcb1f201bf2478a50f91 +size 1966732 diff --git a/linux-arm64/needle b/linux-arm64/needle index 83a603ebab29150a9dcb78c8f37895961a794bbf..7f09d0f13f88483e8050f751ad3a2e9dd7686dfa 100644 --- a/linux-arm64/needle +++ b/linux-arm64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89bcfac2e0c38f70818e7c8936c4f8be2a8eb27eb8eb19a8babea303470afee4 -size 1168392 +oid sha256:bcf48b66a3e1834e8cb92c9f9998d85d4618d3e949c8a9d293116749a1f0d205 +size 1409312 diff --git a/linux-arm64/needle.h b/linux-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/linux-arm64/needle.h +++ b/linux-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/linux-armv7/libneedle.a b/linux-armv7/libneedle.a index eced7f7144f54754edd2a4501130698f24945f7f..6b10135f3099c22c3dee2bad593d34f8a043d292 100644 --- a/linux-armv7/libneedle.a +++ b/linux-armv7/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35f35346813228971ee43947a136341c6b5ebf8c159ce30849822f02a1c868f8 -size 1358386 +oid sha256:f3cdfcc9a5e9aa3afcd0af6612fe2d6099f85c31b7fb5a7d486e3362e7e60c57 +size 1732630 diff --git a/linux-armv7/needle b/linux-armv7/needle index 9a569bf6a01d604dbcb50b6d9b60d4a14a0bf00a..1092cc433f9428417ba476c569edd70d85a9a494 100644 --- a/linux-armv7/needle +++ b/linux-armv7/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01d69ae6dcd1fafa156192480fbe0cb879b1338bf9b568dc562dac2ad8af2d2a -size 998124 +oid sha256:9eea74cba1f8660b1d1835d5d1704559bdf06af6736cfa6dc403e9edc19da0a6 +size 1216328 diff --git a/linux-armv7/needle.h b/linux-armv7/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/linux-armv7/needle.h +++ b/linux-armv7/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/linux-mipsel/libneedle.a b/linux-mipsel/libneedle.a index 12184c6a87b86f13ede2dbd0f9fda867b99f1c4a..1875b83903629b030d429eecbdfbf3a7aab07e77 100644 --- a/linux-mipsel/libneedle.a +++ b/linux-mipsel/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8b21452eb0fdd22fe07edd40b11032de7c9d425ff07406d8c5373fb98557f28 -size 1307030 +oid sha256:3a17c4c012075510c9f24321a98259dd02a2d6e03adf11a492c5951d1cbd5b7e +size 1636470 diff --git a/linux-mipsel/needle b/linux-mipsel/needle index 42f3a6f29d894e7ce1109c5f3aba7a6e418f2ade..4e29d67fd97ee35dce9cc8135b93a7a814f94ab8 100644 --- a/linux-mipsel/needle +++ b/linux-mipsel/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:275515de7bb763ce910d67fc7dfeff3c8db5976d17fdb363bda2330f4a52e24d -size 1489036 +oid sha256:48aba03a7fd1575c9f0a26a864b04f714e0caba91f311073534dcb331e7b0f98 +size 1773672 diff --git a/linux-mipsel/needle.h b/linux-mipsel/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/linux-mipsel/needle.h +++ b/linux-mipsel/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/linux-riscv64/libneedle.a b/linux-riscv64/libneedle.a index e88277e9de2adb2167c96d8790bf5c2306df766f..3868f558195850ea21fcf1aa1a48099d15be6b39 100644 --- a/linux-riscv64/libneedle.a +++ b/linux-riscv64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcee5b99bc70cecf7a6125d99b68bd9f4239909fa702bb7e7c7fac2bf8eb0f20 -size 1550336 +oid sha256:6e84c1fac7562fc507962a26dd1f25ae4203f755ab16104551fe365dc0833c05 +size 1881996 diff --git a/linux-riscv64/needle b/linux-riscv64/needle index 54e55ace64e7855481562aafb9c3708b423042b6..b7df21db6ed3762bd6b5e0f1eed8b242beb1f367 100644 --- a/linux-riscv64/needle +++ b/linux-riscv64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b80680c617dd5cf675efe4f37dc89554dc30c8c51ca5509f734e6785c5b2888c -size 998272 +oid sha256:a95e703c00e0a8b053e5829c10fd684e387d5fab76adb1c317f8f0a30e2e2c45 +size 1157928 diff --git a/linux-riscv64/needle.h b/linux-riscv64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/linux-riscv64/needle.h +++ b/linux-riscv64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/linux-x86_64/libneedle.a b/linux-x86_64/libneedle.a index e274c42450f9819ae0806137a73251114eccace9..dd5211db585e78e843a473da6dd446cef7ced330 100644 --- a/linux-x86_64/libneedle.a +++ b/linux-x86_64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35581b09da9b012637718d74dfb03c6ca563839bd909f2602c1b96764a916566 -size 1676548 +oid sha256:5c0ff309dcf9c2238bd07986d9d100069d568596c2378f0bfedc1677cc02f756 +size 2143656 diff --git a/linux-x86_64/needle b/linux-x86_64/needle index d3b9689e3b92c1bc7b62f01dcaef31eadbae5377..4b76ae438be2d8f487d8ea361682f733be72dbd3 100644 --- a/linux-x86_64/needle +++ b/linux-x86_64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a5e3baf782b8773f704048936e2380d675ba3bc1f41f441b748048b554ffc846 -size 1248608 +oid sha256:b197ceaef3b300a0b14c3a4fde92305527e43f9256c53d2a53d2a2fe8fe69678 +size 1517200 diff --git a/linux-x86_64/needle.h b/linux-x86_64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/linux-x86_64/needle.h +++ b/linux-x86_64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/macos-arm64/libneedle.a b/macos-arm64/libneedle.a index 9ae328cda1f75149051a3d69d5097ffb77934d79..017c5f369d8e2f5ee4f4c606d79358946c69cf78 100644 --- a/macos-arm64/libneedle.a +++ b/macos-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e9e0d01dc1ac0438f2890e5f51fec48fd6eadce1cd2c4455ccc13eb735838bb -size 1158848 +oid sha256:a3b9163abe7b4bd52487c4005506cb35c5163bb9b9587af4ae07ed7587de697d +size 1503976 diff --git a/macos-arm64/needle b/macos-arm64/needle index 9f4ae5892f8f0f8ad17b78c6c32f1dc400c52835..0fd2b76c722129a836d4e7b46d6124e1de3d4468 100644 --- a/macos-arm64/needle +++ b/macos-arm64/needle @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4091895e4dcc8936aa1c813912dd77484a6cdf73437c07dd1af1b64123ab9620 -size 824792 +oid sha256:f52c9ce7c05ef44e8d8441584aec9e6ac6054f811866eacd70f33da2462577dc +size 1073160 diff --git a/macos-arm64/needle.h b/macos-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/macos-arm64/needle.h +++ b/macos-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/python/cactus_needle-3.1.0-py3-none-macosx_11_0_arm64.whl b/python/cactus_needle-3.1.0-py3-none-macosx_11_0_arm64.whl new file mode 100644 index 0000000000000000000000000000000000000000..b1d9ddbbec1d54c22bbe9a0bd00db244712b8d47 --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-macosx_11_0_arm64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad1cba80ede4c058692370964eec4d881a1fdc80014f7210b2d13891bad7d1c6 +size 523657 diff --git a/python/cactus_needle-3.1.0-py3-none-macosx_11_0_x86_64.whl b/python/cactus_needle-3.1.0-py3-none-macosx_11_0_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..e8d622f2c93200da45d37f04d70442c9673fa481 --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-macosx_11_0_x86_64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31a90adbaa898ea65e92b370e80ba5830a346348022a913a8bb254ab7d20bad6 +size 575529 diff --git a/python/cactus_needle-3.1.0-py3-none-manylinux2014_aarch64.whl b/python/cactus_needle-3.1.0-py3-none-manylinux2014_aarch64.whl new file mode 100644 index 0000000000000000000000000000000000000000..fb67462c5449d3eef05934d484c543b8514ac20f --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-manylinux2014_aarch64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2f30a1178856025ab4bf75ef75e1bf28b8d0552cdd5614f7d06cedc1f713606 +size 649611 diff --git a/python/cactus_needle-3.1.0-py3-none-manylinux2014_x86_64.whl b/python/cactus_needle-3.1.0-py3-none-manylinux2014_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..8f4552bdcb14a003f11e958c25f09b3fb6ab29ff --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-manylinux2014_x86_64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0fc2f682ef18525d4d18583081ac31c1f6f211abe6c0b3bee44811ed7e0347e +size 671203 diff --git a/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_aarch64.whl b/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_aarch64.whl new file mode 100644 index 0000000000000000000000000000000000000000..eaacfe4a494bda92ce1c1d7bce63ebaba8981439 --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_aarch64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5e3c48b2c181d29117949f4f55c57cab8c3ccd08d782302b56489fde9c15f73 +size 649438 diff --git a/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_x86_64.whl b/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..373a7c98733a0a209263a31936f20768ef7864c9 --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-musllinux_1_2_x86_64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:835ea0d5765704b65bfaf286e2e94aa2e6027b9494a18adf0fb845f2e3bc7a04 +size 672183 diff --git a/python/cactus_needle-3.1.0-py3-none-win_amd64.whl b/python/cactus_needle-3.1.0-py3-none-win_amd64.whl new file mode 100644 index 0000000000000000000000000000000000000000..999a28c723480539ede597998a67e8fe36b85684 --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-win_amd64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f5fc86abfc50d551cdb237a34b501f36d82d4b6f5911ee7bec4e9532d44dd95 +size 683889 diff --git a/python/cactus_needle-3.1.0-py3-none-win_arm64.whl b/python/cactus_needle-3.1.0-py3-none-win_arm64.whl new file mode 100644 index 0000000000000000000000000000000000000000..15a07c2b69fbda56c046f265f1eb6c0070e4cfab --- /dev/null +++ b/python/cactus_needle-3.1.0-py3-none-win_arm64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39806d54910c207cd0ac5dc60009c8c5330072ef729711d74061faf0e99e7a6c +size 617795 diff --git a/tvos-arm64/libneedle.a b/tvos-arm64/libneedle.a index 7429ac7b9dbabeee2f83b798f993c326ef7d95fe..a2dc659c1b0161b9dfb372ab2fe1038688d9ca2e 100644 --- a/tvos-arm64/libneedle.a +++ b/tvos-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f15c4920b1456cdeddfa17fbb7e7d625ee585fdad5dd33a6393997b62859632f -size 1137944 +oid sha256:fe1105a1f377f40a79a225336256e2cc2b8da18836d0871f549afb31099a6d76 +size 1465744 diff --git a/tvos-arm64/needle.h b/tvos-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/tvos-arm64/needle.h +++ b/tvos-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/wasm-component/needle.component.wasm b/wasm-component/needle.component.wasm index 00f66832c5451abc0d354b0d565db215ae2f2cfe..2189c146ff981c8310ff0b650bc9097ea0412070 100644 --- a/wasm-component/needle.component.wasm +++ b/wasm-component/needle.component.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fc4eb9927c1cbf8894dc107f18741c06cf98518d7023ef2b24b8103fbd393ce -size 4174239 +oid sha256:5c07eba8742a3d76c1d7bfbef8129210a70b44e0e7fdcaecdece67f7a4bc4678 +size 4452455 diff --git a/wasm/needle.h b/wasm/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/wasm/needle.h +++ b/wasm/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/wasm/needle.js b/wasm/needle.js index f5f8b957cb610ba360a59cce23d33ef3cb7e28a5..13b37fca41dbc8d22b82d2e9d2a184f6c8e837b2 100644 --- a/wasm/needle.js +++ b/wasm/needle.js @@ -1,2 +1,2 @@ -var createNeedle=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var programArgs=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}programArgs=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAP64=new BigInt64Array(b)}function preRun(){}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();TTY.init();wasmExports["r"]();FS.ignorePermissions=false}function postRun(){}function abort(what){what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("needle.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var HEAPU32;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);uncaughtExceptionCount++;abort()};var HEAP32;var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.slice(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.slice(0,-1)}return root+dir},basename:path=>path&&path.match(/([^\/]+|\/)\/*$/)[1],join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(ENVIRONMENT_IS_NODE){var nodeCrypto=require("node:crypto");return view=>(nodeCrypto.randomFillSync(view),0)}return view=>(crypto.getRandomValues(view),0)};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).slice(1);to=PATH_FS.resolve(to).slice(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var intArrayFromString=(stringy,dontAddNull,length)=>{var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array};var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(globalThis.window?.prompt){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output?.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var HEAPU8;var zeroMemory=(ptr,size)=>HEAPU8.fill(0,ptr,ptr+size);var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=MEMFS.emptyFileContents??=new Uint8Array(0)}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){return node.contents.subarray(0,node.usedBytes)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents.length;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity)newCapacity=Math.max(newCapacity,256);var oldContents=MEMFS.getFileDataAsTypedArray(node);node.contents=new Uint8Array(newCapacity);node.contents.set(oldContents)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;var oldContents=node.contents;node.contents=new Uint8Array(newSize);node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));node.usedBytes=newSize},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]!=null){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){if(!MEMFS.doesNotExistError){MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack=""}throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);buffer.set(contents.subarray(position,position+size),offset);return size},write(stream,buffer,offset,length,position,canOwn){if(buffer.buffer===HEAP8.buffer){canOwn=false}if(!length)return 0;var node=stream.node;node.mtime=node.ctime=Date.now();if(canOwn){node.contents=buffer.subarray(offset,offset+length);node.usedBytes=length}else if(node.usedBytes===0&&position===0){node.contents=buffer.slice(offset,offset+length);node.usedBytes=length}else{MEMFS.expandFileStorage(node,position+length);node.contents.set(buffer.subarray(offset,offset+length),position);node.usedBytes=Math.max(node.usedBytes,position+length)}return length},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.usedBytes}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr;var allocated;var contents=stream.node.contents;if(!(flags&2)&&contents.buffer===HEAP8.buffer){allocated=false;ptr=contents.byteOffset}else{allocated=true;ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}if(contents){if(position>0||position+length{if(typeof str!="string")return str;var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_fileDataToTypedArray=data=>{if(typeof data=="string"){data=intArrayFromString(data,true)}if(!data.subarray){data=new Uint8Array(data)}return data};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var FS_createDataFile=(...args)=>FS.createDataFile(...args);var getUniqueRunDependency=id=>id;var dependenciesPromise=null;var resolveRunDependencies=async()=>dependenciesPromise;var runDependencies=0;var dependenciesPromiseResolve=null;var removeRunDependency=id=>{runDependencies--;if(!runDependencies){dependenciesPromiseResolve()}};var addRunDependency=id=>{if(!runDependencies){dependenciesPromise=new Promise(resolve=>dependenciesPromiseResolve=resolve)}runDependencies++};var preloadPlugins=[];var FS_handledByPreloadPlugin=async(byteArray,fullname)=>{if(typeof Browser!="undefined")Browser.init();for(var plugin of preloadPlugins){if(plugin["canHandle"](fullname)){return plugin["handle"](byteArray,fullname)}}return byteArray};var FS_preloadFile=async(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);addRunDependency(dep);try{var byteArray=url;if(typeof url=="string"){byteArray=await asyncLoad(url)}byteArray=await FS_handledByPreloadPlugin(byteArray,fullname);preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}}finally{removeRunDependency(dep)}};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{FS_preloadFile(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish).then(onload).catch(onerror)};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,filesystems:null,syncFSRequests:0,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}addListener(cb,exclusive=false){var entry={cb,exclusive};var listeners=this.listeners??=new Set;listeners.add(entry);return{listeners,entry}}notifyListeners(flags){if(!this.listeners)return;var excl;for(var entry of this.listeners){if(entry.exclusive)(excl||=[]).push(entry);else entry.cb(flags)}if(excl){var i=(this.exclTurn||0)%excl.length;this.exclTurn=i+1;excl[i].cb(flags)}}},lookupPath(path,opts={}){if(!path){throw new FS.ErrnoError(44)}opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}if(perms.includes("w")&&!(node.mode&146)){return 2}if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else if(FS.isDir(node.mode)){return 31}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}var mode=FS.flagsToPermissionString(flags);if(FS.isDir(node.mode)){if(mode!=="r"||flags&(512|64)){return 31}}return FS.nodePermissions(node,mode)},checkOpExists(op,err){if(!op){throw new FS.ErrnoError(err)}return op},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},doSetAttr(stream,node,attr){var setattr=stream?.stream_ops.setattr;var arg=setattr?stream:node;setattr??=node.node_ops.setattr;FS.checkOpExists(setattr,63);try{setattr(arg,attr)}catch(e){if(e instanceof RangeError){throw new FS.ErrnoError(22)}throw e}},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}for(var mount of mounts){if(mount.type.syncfs){mount.type.syncfs(mount,populate,done)}else{done(null)}}},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);for(var[hash,current]of Object.entries(FS.nameTable)){while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}}node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name){throw new FS.ErrnoError(28)}if(name==="."||name===".."){throw new FS.ErrnoError(20)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){return FS.statfsNode(FS.lookupPath(path,{follow:true}).node)},statfsStream(stream){return FS.statfsNode(stream.node)},statfsNode(node){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};if(node.node_ops.statfs){Object.assign(rtn,node.node_ops.statfs(node.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var dir of dirs){if(!dir)continue;if(d||PATH.isAbs(path))d+="/";d+=dir;try{FS.mkdir(d,mode)}catch(e){if(e.errno!=20)throw e}}},mkdev(path,mode,dev){if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink(oldpath,newpath){if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},link(oldpath,newpath,flags){var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.link){throw new FS.ErrnoError(34)}return parent.node_ops.link(parent,newname,oldpath,flags)},rename(old_path,new_path){var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name);old_node.parent=new_dir}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir(path){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var readdir=FS.checkOpExists(node.node_ops.readdir,54);return readdir(node)},unlink(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink(path){var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return link.node_ops.readlink(link)},stat(path,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;var getattr=FS.checkOpExists(node.node_ops.getattr,63);return getattr(node)},fstat(fd){var stream=FS.getStreamChecked(fd);var node=stream.node;var getattr=stream.stream_ops.getattr;var arg=getattr?stream:node;getattr??=node.node_ops.getattr;FS.checkOpExists(getattr,63);return getattr(arg)},lstat(path){return FS.stat(path,true)},doChmod(stream,node,mode,dontFollow){FS.doSetAttr(stream,node,{mode:mode&4095|node.mode&~4095,ctime:Date.now(),dontFollow})},chmod(path,mode,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChmod(null,node,mode,dontFollow)},lchmod(path,mode){FS.chmod(path,mode,true)},fchmod(fd,mode){var stream=FS.getStreamChecked(fd);FS.doChmod(stream,stream.node,mode,false)},doChown(stream,node,dontFollow){FS.doSetAttr(stream,node,{timestamp:Date.now(),dontFollow})},chown(path,uid,gid,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChown(null,node,dontFollow)},lchown(path,uid,gid){FS.chown(path,uid,gid,true)},fchown(fd,uid,gid){var stream=FS.getStreamChecked(fd);FS.doChown(stream,stream.node,false)},doTruncate(stream,node,len){if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}FS.doSetAttr(stream,node,{size:len,timestamp:Date.now()})},truncate(path,len){if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}FS.doTruncate(null,node,len)},ftruncate(fd,len){var stream=FS.getStreamChecked(fd);if(len<0||(stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.doTruncate(stream,stream.node,len)},utime(path,atime,mtime,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});FS.doSetAttr(null,lookup.node,{atime,mtime,dontFollow})},open(path,flags,mode=438){if(path===""){throw new FS.ErrnoError(44)}flags=FS_modeStringToFlags(flags);if(flags&64){mode=mode&4095|32768}else{mode=0}var node;var isDirPath;if(typeof path=="object"){node=path}else{isDirPath=path.endsWith("/");var lookup=FS.lookupPath(path,{follow:!(flags&131072),noent_okay:true});node=lookup.node;path=lookup.path}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else if(isDirPath){throw new FS.ErrnoError(31)}else{node=FS.mknod(path,mode|511,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node,path:FS.getPath(node),flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(created){FS.chmod(node,mode&511)}return stream},close(stream){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;stream.node?.notifyListeners(32);try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed(stream){return stream.fd===null},llseek(stream,offset,whence){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read(stream,buffer,offset,length,position){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write(stream,buffer,offset,length,position,canOwn){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},mmap(stream,length,position,prot,flags){if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}if(!length){throw new FS.ErrnoError(28)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync(stream,buffer,offset,length,mmapFlags){if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags??0;opts.encoding=opts.encoding??"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){abort(`Invalid encoding type "${opts.encoding}"`)}var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){buf=UTF8ArrayToString(buf)}FS.close(stream);return buf},writeFile(path,data,opts={}){opts.flags=opts.flags??577;var stream=FS.open(path,opts.flags,opts.mode);data=FS_fileDataToTypedArray(data);FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn);FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomFill(randomBuffer);randomLeft=randomBuffer.byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var stream of FS.streams){if(stream){FS.close(stream)}}},findObject(path,dontResolveLastLink){var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath(path,dontResolveLastLink){try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath(parent,path,canRead,canWrite){parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){if(e.errno!=20)throw e}parent=current}return current},createFile(parent,name,properties,canRead,canWrite){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile(parent,name,data,canRead,canWrite,canOwn){var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){data=FS_fileDataToTypedArray(data);FS.chmod(node,mode|146);var stream=FS.open(node,577);FS.write(stream,data,0,data.length,0,canOwn);FS.close(stream);FS.chmod(node,mode)}},createDevice(parent,name,input,output){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(!!input,!!output);FS.createDevice.major??=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open(stream){stream.seekable=false},close(stream){if(output?.buffer?.length){output(10)}},read(stream,buffer,offset,length,pos){var bytesRead=0;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort(`Couldn't load ${url}. Status: ${xhr.status}`);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)abort(`invalid range (${from}, ${to}) or no bytes requested!`);if(to>datalength-1)abort(`only ${datalength} bytes available! programmer error!`);var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range",`bytes=${from}-${to}`);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort(`Couldn't load ${url}. Status: ${xhr.status}`);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText??"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")abort("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(globalThis.XMLHttpRequest){if(!ENVIRONMENT_IS_WORKER)abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc");var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};for(const[key,fn]of Object.entries(node.stream_ops)){stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}}function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var HEAP64;var SYSCALLS={currentUmask:18,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},writeStat(buf,stat){HEAPU32[buf>>2]=stat.dev;HEAPU32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAPU32[buf+12>>2]=stat.uid;HEAPU32[buf+16>>2]=stat.gid;HEAPU32[buf+20>>2]=stat.rdev;HEAP64[buf+24>>3]=BigInt(stat.size);HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;HEAP64[buf+56>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>3]=BigInt(stat.ino);return 0},writeStatFs(buf,stats){HEAPU32[buf+4>>2]=stats.bsize;HEAPU32[buf+60>>2]=stats.bsize;HEAP64[buf+8>>3]=BigInt(stats.blocks);HEAP64[buf+16>>3]=BigInt(stats.bfree);HEAP64[buf+24>>3]=BigInt(stats.bavail);HEAP64[buf+32>>3]=BigInt(stats.files);HEAP64[buf+40>>3]=BigInt(stats.ffree);HEAPU32[buf+48>>2]=stats.fsid;HEAPU32[buf+64>>2]=stats.flags;HEAPU32[buf+56>>2]=stats.namelen},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.subarray(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};var HEAP16;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();var mask=289792;stream.flags=stream.flags&~mask|arg&mask;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>2]=termios.c_iflag||0;HEAP32[argp+4>>2]=termios.c_oflag||0;HEAP32[argp+8>>2]=termios.c_cflag||0;HEAP32[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>2];var c_oflag=HEAP32[argp+4>>2];var c_cflag=HEAP32[argp+8>>2];var c_lflag=HEAP32[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21537:case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>1]=winsize[0];HEAP16[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;if(flags&64){mode&=~SYSCALLS.currentUmask}return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(!flags){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{return-28}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);function __munmap_js(addr,len,prot,flags,fd,offset){offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var _emscripten_get_now=()=>performance.now();var _emscripten_date_now=()=>Date.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP64[ptime>>3]=BigInt(nsec);return 0}var getHeapMax=()=>2147483648;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram;var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(globalThis.navigator?.language??"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;var envp=0;for(var string of getEnvStrings()){var ptr=environ_buf+bufSize;HEAPU32[__environ+envp>>2]=ptr;bufSize+=stringToUTF8(string,ptr,Infinity)+1;envp+=4}return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;for(var string of strings){bufSize+=lengthBytesUTF8(string)+1}HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;try{var curr=FS.read(stream,HEAP8,ptr,len,offset)}catch(e){if(ret>0&&e instanceof FS.ErrnoError&&(e.errno==6||e.errno==6)){break}throw e}if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 22;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{if(iovcnt==1){return FS.write(stream,HEAP8,HEAPU32[iov>>2],HEAPU32[iov+4>>2],offset)}var total=0;for(var i=0,p=iov;i>2]}var view=new Uint8Array(total);var voff=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];view.set(HEAPU8.subarray(ptr,ptr+len),voff);voff+=len}return FS.write(stream,view,0,total,offset)};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};FS.createPreloadedFile=FS_createPreloadedFile;FS.preloadFile=FS_preloadFile;FS.staticInit();{if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"]}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["UTF8ToString"]=UTF8ToString;var _needle_load,_needle_init,_needle_reset,_needle_complete,_needle_embed,_free,_malloc,_emscripten_builtin_memalign,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_needle_load=Module["_needle_load"]=wasmExports["s"];_needle_init=Module["_needle_init"]=wasmExports["t"];_needle_reset=Module["_needle_reset"]=wasmExports["u"];_needle_complete=Module["_needle_complete"]=wasmExports["v"];_needle_embed=Module["_needle_embed"]=wasmExports["w"];_free=Module["_free"]=wasmExports["x"];_malloc=Module["_malloc"]=wasmExports["y"];_emscripten_builtin_memalign=wasmExports["z"];__emscripten_stack_restore=wasmExports["A"];__emscripten_stack_alloc=wasmExports["B"];_emscripten_stack_get_current=wasmExports["C"];memory=wasmMemory=wasmExports["q"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:___cxa_throw,d:___syscall_fcntl64,i:___syscall_ioctl,p:___syscall_openat,n:___syscall_rmdir,o:___syscall_unlinkat,e:__abort_js,f:__munmap_js,l:_clock_time_get,m:_emscripten_resize_heap,j:_environ_get,k:_environ_sizes_get,b:_fd_close,h:_fd_read,g:_fd_seek,c:_fd_write};async function run(){preRun();if(runDependencies){await resolveRunDependencies()}if(ABORT)return;initRuntime();postRun()}var wasmExports;wasmExports=await createWasm();await run(); +var createNeedle=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var programArgs=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}programArgs=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");class EmscriptenEH{}class EmscriptenSjLj extends EmscriptenEH{}var runtimeInitialized=false;function getMemoryBuffer(){return wasmMemory.buffer}function updateMemoryViews(){if(HEAP8?.buffer?.resizable)return;var b=getMemoryBuffer();HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);HEAP32=new Int32Array(b);HEAPU32=new Uint32Array(b);HEAP64=new BigInt64Array(b)}function preRun(){}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();TTY.init();wasmExports["r"]();FS.ignorePermissions=false}function postRun(){}function abort(what){what=`Aborted(${what})`;err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("needle.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP8;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var HEAPU32;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);uncaughtExceptionCount++;abort()};var HEAP32;var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.slice(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.slice(0,-1)}return root+dir},basename:path=>path&&path.match(/([^\/]+|\/)\/*$/)[1],join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(ENVIRONMENT_IS_NODE){var nodeCrypto=require("node:crypto");return view=>(nodeCrypto.randomFillSync(view),0)}return view=>(crypto.getRandomValues(view),0)};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).slice(1);to=PATH_FS.resolve(to).slice(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var intArrayFromString=(stringy,dontAddNull,length)=>{var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array};var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}}else if(globalThis.window?.prompt){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output?.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var HEAPU8;var zeroMemory=(ptr,size)=>HEAPU8.fill(0,ptr,ptr+size);var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=MEMFS.emptyFileContents??=new Uint8Array(0)}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){return node.contents.subarray(0,node.usedBytes)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents.length;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity)newCapacity=Math.max(newCapacity,256);var oldContents=MEMFS.getFileDataAsTypedArray(node);node.contents=new Uint8Array(newCapacity);node.contents.set(oldContents)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;var oldContents=node.contents;node.contents=new Uint8Array(newSize);node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)));node.usedBytes=newSize},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]!=null){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){if(!MEMFS.doesNotExistError){MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack=""}throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);buffer.set(contents.subarray(position,position+size),offset);return size},write(stream,buffer,offset,length,position,canOwn){if(buffer.buffer===HEAP8.buffer){canOwn=false}if(!length)return 0;var node=stream.node;node.mtime=node.ctime=Date.now();if(canOwn){node.contents=buffer.subarray(offset,offset+length);node.usedBytes=length}else if(node.usedBytes===0&&position===0){node.contents=buffer.slice(offset,offset+length);node.usedBytes=length}else{MEMFS.expandFileStorage(node,position+length);node.contents.set(buffer.subarray(offset,offset+length),position);node.usedBytes=Math.max(node.usedBytes,position+length)}return length},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.usedBytes}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr;var allocated;var contents=stream.node.contents;if(!(flags&2)&&contents.buffer===HEAP8.buffer){allocated=false;ptr=contents.byteOffset}else{allocated=true;ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}if(contents){if(position>0||position+length{if(typeof str!="string")return str;var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_fileDataToTypedArray=data=>{if(typeof data=="string"){data=intArrayFromString(data,true)}if(!data.subarray){data=new Uint8Array(data)}return data};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var FS_createDataFile=(...args)=>FS.createDataFile(...args);var getUniqueRunDependency=id=>id;var dependenciesPromise=null;var resolveRunDependencies=async()=>dependenciesPromise;var runDependencies=0;var dependenciesPromiseResolve=null;var removeRunDependency=id=>{runDependencies--;if(!runDependencies){dependenciesPromiseResolve()}};var addRunDependency=id=>{if(!runDependencies){dependenciesPromise=new Promise(resolve=>dependenciesPromiseResolve=resolve)}runDependencies++};var preloadPlugins=[];var FS_handledByPreloadPlugin=async(byteArray,fullname)=>{if(typeof Browser!="undefined")Browser.init();for(var plugin of preloadPlugins){if(plugin["canHandle"](fullname)){return plugin["handle"](byteArray,fullname)}}return byteArray};var FS_preloadFile=async(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);addRunDependency(dep);try{var byteArray=url;if(typeof url=="string"){byteArray=await asyncLoad(url)}byteArray=await FS_handledByPreloadPlugin(byteArray,fullname);preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}}finally{removeRunDependency(dep)}};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{FS_preloadFile(parent,name,url,canRead,canWrite,dontCreateFile,canOwn,preFinish).then(onload).catch(onerror)};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,filesystems:null,syncFSRequests:0,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}addListener(cb,exclusive=false){var entry={cb,exclusive};var listeners=this.listeners??=new Set;listeners.add(entry);return{listeners,entry}}notifyListeners(flags){if(!this.listeners)return;var excl;for(var entry of this.listeners){if(entry.exclusive)(excl||=[]).push(entry);else entry.cb(flags)}if(excl){var i=(this.exclTurn||0)%excl.length;this.exclTurn=i+1;excl[i].cb(flags)}}},lookupPath(path,opts={}){if(!path){throw new FS.ErrnoError(44)}opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}if(perms.includes("w")&&!(node.mode&146)){return 2}if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else if(FS.isDir(node.mode)){return 31}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}var mode=FS.flagsToPermissionString(flags);if(FS.isDir(node.mode)){if(mode!=="r"||flags&(512|64)){return 31}}return FS.nodePermissions(node,mode)},checkOpExists(op,err){if(!op){throw new FS.ErrnoError(err)}return op},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},doSetAttr(stream,node,attr){var setattr=stream?.stream_ops.setattr;var arg=setattr?stream:node;setattr??=node.node_ops.setattr;FS.checkOpExists(setattr,63);try{setattr(arg,attr)}catch(e){if(e instanceof RangeError){throw new FS.ErrnoError(22)}throw e}},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}for(var mount of mounts){if(mount.type.syncfs){mount.type.syncfs(mount,populate,done)}else{done(null)}}},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);for(var[hash,current]of Object.entries(FS.nameTable)){while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}}node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name){throw new FS.ErrnoError(28)}if(name==="."||name===".."){throw new FS.ErrnoError(20)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){return FS.statfsNode(FS.lookupPath(path,{follow:true}).node)},statfsStream(stream){return FS.statfsNode(stream.node)},statfsNode(node){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};if(node.node_ops.statfs){Object.assign(rtn,node.node_ops.statfs(node.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var dir of dirs){if(!dir)continue;if(d||PATH.isAbs(path))d+="/";d+=dir;try{FS.mkdir(d,mode)}catch(e){if(e.errno!=20)throw e}}},mkdev(path,mode,dev){if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink(oldpath,newpath){if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},link(oldpath,newpath,flags){var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.link){throw new FS.ErrnoError(34)}return parent.node_ops.link(parent,newname,oldpath,flags)},rename(old_path,new_path){var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name);old_node.parent=new_dir}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir(path){var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;var readdir=FS.checkOpExists(node.node_ops.readdir,54);return readdir(node)},unlink(path){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink(path){var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return link.node_ops.readlink(link)},stat(path,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;var getattr=FS.checkOpExists(node.node_ops.getattr,63);return getattr(node)},fstat(fd){var stream=FS.getStreamChecked(fd);var node=stream.node;var getattr=stream.stream_ops.getattr;var arg=getattr?stream:node;getattr??=node.node_ops.getattr;FS.checkOpExists(getattr,63);return getattr(arg)},lstat(path){return FS.stat(path,true)},doChmod(stream,node,mode,dontFollow){FS.doSetAttr(stream,node,{mode:mode&4095|node.mode&~4095,ctime:Date.now(),dontFollow})},chmod(path,mode,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChmod(null,node,mode,dontFollow)},lchmod(path,mode){FS.chmod(path,mode,true)},fchmod(fd,mode){var stream=FS.getStreamChecked(fd);FS.doChmod(stream,stream.node,mode,false)},doChown(stream,node,dontFollow){FS.doSetAttr(stream,node,{timestamp:Date.now(),dontFollow})},chown(path,uid,gid,dontFollow){var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}FS.doChown(null,node,dontFollow)},lchown(path,uid,gid){FS.chown(path,uid,gid,true)},fchown(fd,uid,gid){var stream=FS.getStreamChecked(fd);FS.doChown(stream,stream.node,false)},doTruncate(stream,node,len){if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}FS.doSetAttr(stream,node,{size:len,timestamp:Date.now()})},truncate(path,len){if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}FS.doTruncate(null,node,len)},ftruncate(fd,len){var stream=FS.getStreamChecked(fd);if(len<0||(stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.doTruncate(stream,stream.node,len)},utime(path,atime,mtime,dontFollow){var lookup=FS.lookupPath(path,{follow:!dontFollow});FS.doSetAttr(null,lookup.node,{atime,mtime,dontFollow})},open(path,flags,mode=438){if(path===""){throw new FS.ErrnoError(44)}flags=FS_modeStringToFlags(flags);if(flags&64){mode=mode&4095|32768}else{mode=0}var node;var isDirPath;if(typeof path=="object"){node=path}else{isDirPath=path.endsWith("/");var lookup=FS.lookupPath(path,{follow:!(flags&131072),noent_okay:true});node=lookup.node;path=lookup.path}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else if(isDirPath){throw new FS.ErrnoError(31)}else{node=FS.mknod(path,mode|511,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node,path:FS.getPath(node),flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(created){FS.chmod(node,mode&511)}return stream},close(stream){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;stream.node?.notifyListeners(32);try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed(stream){return stream.fd===null},llseek(stream,offset,whence){if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read(stream,buffer,offset,length,position){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write(stream,buffer,offset,length,position,canOwn){if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},mmap(stream,length,position,prot,flags){if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}if(!length){throw new FS.ErrnoError(28)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync(stream,buffer,offset,length,mmapFlags){if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags??0;opts.encoding=opts.encoding??"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){abort(`Invalid encoding type "${opts.encoding}"`)}var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){buf=UTF8ArrayToString(buf)}FS.close(stream);return buf},writeFile(path,data,opts={}){opts.flags=opts.flags??577;var stream=FS.open(path,opts.flags,opts.mode);data=FS_fileDataToTypedArray(data);FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn);FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomFill(randomBuffer);randomLeft=randomBuffer.byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var stream of FS.streams){if(stream){FS.close(stream)}}},findObject(path,dontResolveLastLink){var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath(path,dontResolveLastLink){try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath(parent,path,canRead,canWrite){parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){if(e.errno!=20)throw e}parent=current}return current},createFile(parent,name,properties,canRead,canWrite){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile(parent,name,data,canRead,canWrite,canOwn){var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){data=FS_fileDataToTypedArray(data);FS.chmod(node,mode|146);var stream=FS.open(node,577);FS.write(stream,data,0,data.length,0,canOwn);FS.close(stream);FS.chmod(node,mode)}},createDevice(parent,name,input,output){var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(!!input,!!output);FS.createDevice.major??=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open(stream){stream.seekable=false},close(stream){if(output?.buffer?.length){output(10)}},read(stream,buffer,offset,length,pos){var bytesRead=0;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort(`Couldn't load ${url}. Status: ${xhr.status}`);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)abort(`invalid range (${from}, ${to}) or no bytes requested!`);if(to>datalength-1)abort(`only ${datalength} bytes available! programmer error!`);var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range",`bytes=${from}-${to}`);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))abort(`Couldn't load ${url}. Status: ${xhr.status}`);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText??"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")abort("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(globalThis.XMLHttpRequest){if(!ENVIRONMENT_IS_WORKER)abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc");var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};for(const[key,fn]of Object.entries(node.stream_ops)){stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}}function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var HEAP64;var SYSCALLS={currentUmask:18,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},writeStat(buf,stat){HEAPU32[buf>>2]=stat.dev;HEAPU32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAPU32[buf+12>>2]=stat.uid;HEAPU32[buf+16>>2]=stat.gid;HEAPU32[buf+20>>2]=stat.rdev;HEAP64[buf+24>>3]=BigInt(stat.size);HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;HEAP64[buf+56>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>3]=BigInt(stat.ino);return 0},writeStatFs(buf,stats){HEAPU32[buf+4>>2]=stats.bsize;HEAPU32[buf+60>>2]=stats.bsize;HEAP64[buf+8>>3]=BigInt(stats.blocks);HEAP64[buf+16>>3]=BigInt(stats.bfree);HEAP64[buf+24>>3]=BigInt(stats.bavail);HEAP64[buf+32>>3]=BigInt(stats.files);HEAP64[buf+40>>3]=BigInt(stats.ffree);HEAPU32[buf+48>>2]=stats.fsid;HEAPU32[buf+64>>2]=stats.flags;HEAPU32[buf+56>>2]=stats.namelen},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.subarray(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};var HEAP16;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();var mask=289792;stream.flags=stream.flags&~mask|arg&mask;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>2]=termios.c_iflag||0;HEAP32[argp+4>>2]=termios.c_oflag||0;HEAP32[argp+8>>2]=termios.c_cflag||0;HEAP32[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>2];var c_oflag=HEAP32[argp+4>>2];var c_cflag=HEAP32[argp+8>>2];var c_lflag=HEAP32[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21537:case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>1]=winsize[0];HEAP16[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;if(flags&64){mode&=~SYSCALLS.currentUmask}return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(!flags){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{return-28}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);function __munmap_js(addr,len,prot,flags,fd,offset){offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var _emscripten_get_now=()=>performance.now();var _emscripten_date_now=()=>Date.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP64[ptime>>3]=BigInt(nsec);return 0}var getHeapMax=()=>2147483648;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram;var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(globalThis.navigator?.language??"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;var envp=0;for(var string of getEnvStrings()){var ptr=environ_buf+bufSize;HEAPU32[__environ+envp>>2]=ptr;bufSize+=stringToUTF8(string,ptr,Infinity)+1;envp+=4}return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;for(var string of strings){bufSize+=lengthBytesUTF8(string)+1}HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;try{var curr=FS.read(stream,HEAP8,ptr,len,offset)}catch(e){if(ret>0&&e instanceof FS.ErrnoError&&(e.errno==6||e.errno==6)){break}throw e}if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 22;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{if(iovcnt==1){return FS.write(stream,HEAP8,HEAPU32[iov>>2],HEAPU32[iov+4>>2],offset)}var total=0;for(var i=0,p=iov;i>2]}var view=new Uint8Array(total);var voff=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];view.set(HEAPU8.subarray(ptr,ptr+len),voff);voff+=len}return FS.write(stream,view,0,total,offset)};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};FS.createPreloadedFile=FS_createPreloadedFile;FS.preloadFile=FS_preloadFile;FS.staticInit();{if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"]}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["UTF8ToString"]=UTF8ToString;var _needle_last_error,_needle_init,_needle_reset,_needle_transcribe,_needle_load,_needle_models,_needle_set_audio,_needle_complete,_needle_embed,_free,_malloc,_emscripten_builtin_memalign,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_needle_last_error=Module["_needle_last_error"]=wasmExports["s"];_needle_init=Module["_needle_init"]=wasmExports["t"];_needle_reset=Module["_needle_reset"]=wasmExports["u"];_needle_transcribe=Module["_needle_transcribe"]=wasmExports["v"];_needle_load=Module["_needle_load"]=wasmExports["w"];_needle_models=Module["_needle_models"]=wasmExports["x"];_needle_set_audio=Module["_needle_set_audio"]=wasmExports["y"];_needle_complete=Module["_needle_complete"]=wasmExports["z"];_needle_embed=Module["_needle_embed"]=wasmExports["A"];_free=Module["_free"]=wasmExports["B"];_malloc=Module["_malloc"]=wasmExports["C"];_emscripten_builtin_memalign=wasmExports["D"];__emscripten_stack_restore=wasmExports["E"];__emscripten_stack_alloc=wasmExports["F"];_emscripten_stack_get_current=wasmExports["G"];memory=wasmMemory=wasmExports["q"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:___cxa_throw,d:___syscall_fcntl64,i:___syscall_ioctl,p:___syscall_openat,n:___syscall_rmdir,o:___syscall_unlinkat,e:__abort_js,f:__munmap_js,l:_clock_time_get,m:_emscripten_resize_heap,j:_environ_get,k:_environ_sizes_get,b:_fd_close,h:_fd_read,g:_fd_seek,c:_fd_write};async function run(){preRun();if(runDependencies){await resolveRunDependencies()}if(ABORT)return;initRuntime();postRun()}var wasmExports;wasmExports=await createWasm();await run(); ;return Module}})();if(typeof exports==="object"&&typeof module==="object"){module.exports=createNeedle;module.exports.default=createNeedle}else if(typeof define==="function"&&define["amd"])define([],()=>createNeedle); diff --git a/wasm/needle.wasm b/wasm/needle.wasm index b0f4573276d67cced6582162d9db493e86e31c07..39cfc21bee4d86369077f67877ab8f4d2772a47f 100644 --- a/wasm/needle.wasm +++ b/wasm/needle.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:797fcf97d1356e673dc710b92a5b5e644b1e971e3071d03e09774958d1d7cdb2 -size 688713 +oid sha256:c19b9ddf9c7de4eb4f37e5f1811c5bbea9f099041d2a27284daf89789ee8523d +size 903655 diff --git a/watchos-arm64/libneedle.a b/watchos-arm64/libneedle.a index c25b951b34f22a7b678e08b498f5e3f0afd3064e..f70d7208844563794982a8d5a62f1e6cb32e8fc9 100644 --- a/watchos-arm64/libneedle.a +++ b/watchos-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:09be305adadc4e87249bf307daae562ebb6416cbfc5e596ad10ee561aae99941 -size 1134952 +oid sha256:bc0e82958495dc8a9f041faef071b61300c10472b1d3566fcf41934309cdff70 +size 1486712 diff --git a/watchos-arm64/needle.h b/watchos-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/watchos-arm64/needle.h +++ b/watchos-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/windows-arm64/libneedle.a b/windows-arm64/libneedle.a index 21be9ecfe6d1c2dfe13b31871fd91e7f1bd7cf9a..7ecf64f1ab986a05062f38499d00d2a288684fd6 100644 --- a/windows-arm64/libneedle.a +++ b/windows-arm64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61f839286908fe1b3ad710b392f190c18359c9bff34330683f0adbe9e26f874b -size 1652268 +oid sha256:e6c479a4094896785a22c2a54e3c8bfd8f60903488651ad6d4b47685512cec61 +size 2078628 diff --git a/windows-arm64/needle.exe b/windows-arm64/needle.exe index 17383649f91c1d03a7e605489f7de2af57377cb3..baa8d9a77b44c5c0840f6dd2c65bb0fb379d56a4 100644 --- a/windows-arm64/needle.exe +++ b/windows-arm64/needle.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d45bba84c63b1b57442bea3a69b0b89de9dd25a1b6dae3ef9123fd916e73e479 -size 1106944 +oid sha256:078a7659770c5117458abf23b320e7de603aeac8d0d9cbbb31eb65eedbc0795d +size 1331712 diff --git a/windows-arm64/needle.h b/windows-arm64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/windows-arm64/needle.h +++ b/windows-arm64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus diff --git a/windows-x86_64/libneedle.a b/windows-x86_64/libneedle.a index 70f97f3542490a4209beecdc46c84f1adb1279bb..8286c3b3bedb06164700f37fbfec3fbcd02669e8 100644 --- a/windows-x86_64/libneedle.a +++ b/windows-x86_64/libneedle.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d27ba285400fcc50c10df2b60e31bba833911fa73cc406adfe946e86e492d4b -size 1809904 +oid sha256:a2501f416a562bf0c2ad734821dd190571d22ced22c104372b8cd41b40245114 +size 2292578 diff --git a/windows-x86_64/needle.exe b/windows-x86_64/needle.exe index 53fc70128b33fcf88ee6f90b8e7a5b878bb35d36..d641940e40243a9840a8f648110d609c548c0f92 100644 --- a/windows-x86_64/needle.exe +++ b/windows-x86_64/needle.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ed90649989e710c56cd56ea13454633c051612946d40a377869208da5a37dbe -size 1277952 +oid sha256:c70ca998f6c542c862c06c22352046e303ef5c769384069ee25cef9f4667e4cf +size 1540096 diff --git a/windows-x86_64/needle.h b/windows-x86_64/needle.h index 9eb16c8a3771cd1881d3ac634e47f5ba30985ac9..9b404d845f557ed1c9435ab30040219fa3aa81a6 100644 --- a/windows-x86_64/needle.h +++ b/windows-x86_64/needle.h @@ -5,42 +5,89 @@ #define NEEDLE_API __attribute__((visibility("default"))) #endif +#define NEEDLE_TEXT 1 +#define NEEDLE_SPEECH 2 + #ifdef __cplusplus extern "C" { #endif -/* One process-global, non-thread-safe model. Negative returns indicate failure. - needle_init returns the tokenized static-prefix length on success. It can fail - when the system prompt plus statically-declared tools do not fit the model's - context window; call needle_last_error() for the specific reason. */ +/* One process-global, non-thread-safe model per kind, text and speech. + Negative returns indicate failure; call needle_last_error() for the specific + reason. needle_load reads whichever kind the .cact holds and keeps the other, + so a build with both models takes one call per model. */ +NEEDLE_API int needle_load( + const unsigned char* cact, + unsigned long long n +); + +/* NEEDLE_TEXT, NEEDLE_SPEECH or both, for the models this process has loaded. */ +NEEDLE_API int needle_models(void); + +/* Last process-global error, owned by the runtime and valid until the next API call. */ +NEEDLE_API const char* needle_last_error(void); + +/* needle_init returns the tokenized static-prefix length on success. It can fail + when the system prompt plus statically-declared tools exceed the context + window, and reports the measured token count when it does. */ NEEDLE_API int needle_init( const char* system_prompt, const char* tools_json, const char* tool_index_path ); -/* Last process-global error, owned by the runtime and valid until the next API call. */ -NEEDLE_API const char* needle_last_error(void); - +/* Answers text or speech: exactly one of input and pcm is non-null. Given pcm, + the engine transcribes the clip with the loaded speech model, answers the + transcript, and merges the speech fields into the same JSON object under an + audio_ prefix. needle_set_audio chooses how that transcription runs. */ NEEDLE_API int needle_complete( const char* input, + const float* pcm, + int samples, int max_new_tokens, char* out, int out_capacity ); -/* A null output returns the model's embedding dimension without computing. */ -NEEDLE_API int needle_embed( - const char* input, - float* out, - int out_capacity +/* Language, keywords and word timestamps for the transcription needle_complete + runs for itself, with the meanings they have in needle_transcribe. The + strings are copied. Defaults: detect the language, no keywords, no times. */ +NEEDLE_API void needle_set_audio( + const char* language, + const char* keywords, + int word_timestamps ); NEEDLE_API void needle_reset(void); -NEEDLE_API int needle_load( - const unsigned char* cact, - unsigned long long n +/* Transcribes 16 kHz mono float PCM in [-1, 1], at most 30 s, and returns the + number of tokens generated. language is "en", "de", "fr", "es", "it", "nl" or + "pl", or NULL to detect it. keywords is NULL or newline-separated words and + phrases for keyword biasing. out receives JSON with the transcript, the + language used, the milliseconds to the first token and the decoder's tokens + per second after it; silence and steady noise give an empty text and language: + {"text":"...","language":"en","ttft_ms":0.0,"decode_tps":0.0} + A non-zero word_timestamps adds each word with times in seconds: + "words":[{"word":"...","start":0.00,"end":0.00,"probability":0.000}] */ +NEEDLE_API int needle_transcribe( + const float* pcm, + int samples, + const char* language, + const char* keywords, + int word_timestamps, + char* out, + int out_capacity +); + +/* Embeds text or speech: exactly one of input and pcm is non-null. Text returns + the model's embedding dimension, speech one row of that width per 80 ms frame, + flattened. A null output returns the float count without computing. */ +NEEDLE_API int needle_embed( + const char* input, + const float* pcm, + int samples, + float* out, + int out_capacity ); #ifdef __cplusplus