├── .gitignore
├── 00-llama-cpp-enable-main.patch
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── build-multi-thread.sh
├── build-single-thread.sh
├── build.sh
├── docs
├── CNAME
├── example-multi-thread.html
├── example-multi-thread.js
├── example-single-thread.html
├── example-single-thread.js
├── favicon.png
├── img
│ ├── js.png
│ ├── llamacpp.png
│ ├── run-llama-cpp-in-browser-twitter-fs8.png
│ ├── tangledgroup.png
│ └── wasm.png
├── index.html
├── llama-mt
│ ├── actions.js
│ ├── llama.js
│ ├── main-worker.js
│ ├── main.js
│ ├── main.wasm
│ ├── main.worker.mjs
│ └── utility.js
├── llama-st
│ ├── actions.js
│ ├── llama.js
│ ├── main-worker.js
│ ├── main.js
│ ├── main.wasm
│ └── utility.js
└── server.js
├── package-lock.json
├── package.json
└── src
└── llama
├── actions.js
├── llama.js
├── main-worker.js
└── utility.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | # keys
35 | cert.pem
36 | key.pem
37 |
38 | # build
39 | dist/
40 | build/
41 | node_modules/
42 |
--------------------------------------------------------------------------------
/00-llama-cpp-enable-main.patch:
--------------------------------------------------------------------------------
1 | diff --git a/CMakeLists.txt b/CMakeLists.txt
2 | index 427015be..e945a722 100644
3 | --- a/CMakeLists.txt
4 | +++ b/CMakeLists.txt
5 | @@ -1157,6 +1157,7 @@ endif()
6 | #
7 |
8 | add_subdirectory(common)
9 | +add_subdirectory(examples/main)
10 |
11 | if (LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
12 | include(CTest)
13 | diff --git a/examples/main/main.cpp b/examples/main/main.cpp
14 | index 0ed4d79f..74b77cc9 100644
15 | --- a/examples/main/main.cpp
16 | +++ b/examples/main/main.cpp
17 | @@ -911,6 +911,9 @@ int main(int argc, char ** argv) {
18 | llama_save_session_file(ctx, path_session.c_str(), session_tokens.data(), session_tokens.size());
19 | }
20 |
21 | + printf("\n");
22 | + fflush(stdout);
23 | +
24 | llama_print_timings(ctx);
25 | write_logfile(ctx, params, model, input_tokens, output_ss.str(), output_tokens);
26 |
27 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | info@tangledgroup.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Tangled Group
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # llama-cpp-wasm
2 |
3 | **WebAssembly** (Wasm) Build and Bindings for [llama.cpp](https://github.com/ggerganov/llama.cpp) and supported by [Tangled Group, Inc](https://tangledgroup.com).
4 |
5 | 
6 |
7 | ## Online Demos
8 |
9 | https://tangledgroup.github.io/llama-cpp-wasm/
10 |
11 |
12 | ## Build
13 |
14 | ```bash
15 | git clone https://github.com/tangledgroup/llama-cpp-wasm.git
16 | cd llama-cpp-wasm
17 | ./build-single-thread.sh
18 | ./build-multi-thread.sh
19 | ```
20 |
21 | Once build is complete you can find `llama.cpp` built in `dist/llama-st` and `dist/llama-mt` directory.
22 |
23 |
24 | ## Deploy
25 |
26 | Basically, you can copy/paste `dist/llama-st` or `dist/llama-mt` directory after build to your project and use as vanilla JavaScript library/module.
27 |
28 |
29 | **index.html**
30 |
31 | ```html
32 |
33 |
34 |
35 | Prompt:
36 |
37 |
38 |
39 |
40 |
41 | Result:
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | ```
51 |
52 |
53 | **example.js**
54 |
55 | ```javascript
56 | // import { LlamaCpp } from "./llama-st/llama.js";
57 | import { LlamaCpp } from "./llama-mt/llama.js";
58 |
59 | const onModelLoaded = () => {
60 | console.debug('model: loaded');
61 | const prompt = document.querySelector("#prompt").value;
62 | document.querySelector("#result").value = prompt;
63 |
64 | app.run({
65 | prompt: prompt,
66 | ctx_size: 4096,
67 | temp: 0.1,
68 | no_display_prompt: true,
69 | });
70 | }
71 |
72 | const onMessageChunk = (text) => {
73 | console.log(text);
74 | document.querySelector('#result').value += text;
75 | };
76 |
77 | const onComplete = () => {
78 | console.debug('model: completed');
79 | };
80 |
81 | const models = [
82 | 'https://huggingface.co/Qwen/Qwen1.5-0.5B-Chat-GGUF/resolve/main/qwen2-beta-0_5b-chat-q8_0.gguf',
83 | 'https://huggingface.co/Qwen/Qwen1.5-1.8B-Chat-GGUF/resolve/main/qwen1_5-1_8b-chat-q8_0.gguf',
84 | 'https://huggingface.co/stabilityai/stablelm-2-zephyr-1_6b/resolve/main/stablelm-2-zephyr-1_6b-Q4_1.gguf',
85 | 'https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf',
86 | 'https://huggingface.co/TheBloke/phi-2-GGUF/resolve/main/phi-2.Q4_K_M.gguf'
87 | ];
88 |
89 | const model = models[2]; // stablelm-2-zephyr-1_6b
90 |
91 | const app = new LlamaCpp(
92 | model,
93 | onModelLoaded,
94 | onMessageChunk,
95 | onComplete,
96 | );
97 | ```
98 |
99 |
100 | ## Run Example
101 |
102 | First generate self-signed certificate.
103 |
104 | ```bash
105 | openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
106 | ```
107 |
108 | ### Run Single Thread Example
109 |
110 | ```bash
111 | npx http-server -S -C cert.pem
112 | ```
113 |
114 | ### Run Multi-threading Example
115 |
116 | Copy `docs/server.js` to your working directory.
117 |
118 | ```bash
119 | npm i express
120 | node server.js
121 | ```
122 |
123 | Then open in browser: https://127.0.0.1:8080/
124 |
--------------------------------------------------------------------------------
/build-multi-thread.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | LLAMA_CPP_WASM_BUILD_DIR=build
5 | LLAMA_CPP_WASM_DIST_DIR=dist
6 | LLAMA_CPP_WASM_DIST_LLAMA_DIR=$LLAMA_CPP_WASM_DIST_DIR/llama-mt
7 | LLAMA_CPP_GIT_HASH="8c933b7"
8 | LLAMA_CPP_SOURCE_DIR=$LLAMA_CPP_WASM_BUILD_DIR/llama.cpp
9 | LLAMA_CPP_BUILD_DIR=$LLAMA_CPP_WASM_BUILD_DIR/build
10 |
11 | #
12 | # compile llama.cpp
13 | #
14 | if [ -d $LLAMA_CPP_WASM_BUILD_DIR ]; then
15 | rm -rf $LLAMA_CPP_WASM_BUILD_DIR
16 | fi
17 |
18 | mkdir -p $LLAMA_CPP_WASM_BUILD_DIR
19 |
20 | git clone https://github.com/ggerganov/llama.cpp.git $LLAMA_CPP_SOURCE_DIR
21 | cd $LLAMA_CPP_SOURCE_DIR
22 | git reset --hard $LLAMA_CPP_GIT_HASH
23 | git apply ../../00-llama-cpp-enable-main.patch
24 | cd ../..
25 |
26 | mkdir -p $LLAMA_CPP_BUILD_DIR
27 | cd $LLAMA_CPP_BUILD_DIR
28 | emcc --clear-cache
29 | emcmake cmake ../../$LLAMA_CPP_SOURCE_DIR
30 | # export EMCC_CFLAGS="-O3 -pthread -DNDEBUG -flto -s SHARED_MEMORY=1 -s EXPORT_ALL=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s INITIAL_MEMORY=2GB -s MAXIMUM_MEMORY=4GB -s ALLOW_MEMORY_GROWTH -s FORCE_FILESYSTEM=1 -s EXPORTED_FUNCTIONS=_main -s EXPORTED_RUNTIME_METHODS=callMain -s NO_EXIT_RUNTIME=1"
31 | export EMCC_CFLAGS="-O3 -msimd128 -pthread -fno-rtti -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=32 -DNDEBUG -flto=full -s SHARED_MEMORY=1 -s EXPORT_ALL=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s INITIAL_MEMORY=800MB -s MAXIMUM_MEMORY=4GB -s ALLOW_MEMORY_GROWTH -s FORCE_FILESYSTEM=1 -s EXPORTED_FUNCTIONS=_main -s EXPORTED_RUNTIME_METHODS=callMain -s NO_EXIT_RUNTIME=1"
32 | emmake make main -j
33 | cd ../..
34 |
35 | #
36 | # bundle llama-cpp-wasm dist
37 | #
38 | if [ -d $LLAMA_CPP_WASM_DIST_LLAMA_DIR ]; then
39 | rm -rf $LLAMA_CPP_WASM_DIST_LLAMA_DIR
40 | fi
41 |
42 | mkdir -p $LLAMA_CPP_WASM_DIST_LLAMA_DIR
43 | cp -rv src/llama/* $LLAMA_CPP_WASM_DIST_LLAMA_DIR
44 | cp $LLAMA_CPP_BUILD_DIR/bin/main.* $LLAMA_CPP_WASM_DIST_LLAMA_DIR
45 |
46 | rm -rf docs/llama-mt
47 | cp -rv $LLAMA_CPP_WASM_DIST_LLAMA_DIR docs/
--------------------------------------------------------------------------------
/build-single-thread.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | LLAMA_CPP_WASM_BUILD_DIR=build
5 | LLAMA_CPP_WASM_DIST_DIR=dist
6 | LLAMA_CPP_WASM_DIST_LLAMA_DIR=$LLAMA_CPP_WASM_DIST_DIR/llama-st
7 | LLAMA_CPP_GIT_HASH="8c933b7"
8 | LLAMA_CPP_SOURCE_DIR=$LLAMA_CPP_WASM_BUILD_DIR/llama.cpp
9 | LLAMA_CPP_BUILD_DIR=$LLAMA_CPP_WASM_BUILD_DIR/build
10 |
11 | #
12 | # compile llama.cpp
13 | #
14 | if [ -d $LLAMA_CPP_WASM_BUILD_DIR ]; then
15 | rm -rf $LLAMA_CPP_WASM_BUILD_DIR
16 | fi
17 |
18 | mkdir -p $LLAMA_CPP_WASM_BUILD_DIR
19 |
20 | git clone https://github.com/ggerganov/llama.cpp.git $LLAMA_CPP_SOURCE_DIR
21 | cd $LLAMA_CPP_SOURCE_DIR
22 | git reset --hard $LLAMA_CPP_GIT_HASH
23 | git apply ../../00-llama-cpp-enable-main.patch
24 | cd ../..
25 |
26 | mkdir -p $LLAMA_CPP_BUILD_DIR
27 | cd $LLAMA_CPP_BUILD_DIR
28 | emcc --clear-cache
29 | emcmake cmake ../../$LLAMA_CPP_SOURCE_DIR
30 | # export EMCC_CFLAGS="-O3 -DNDEBUG -flto -s BUILD_AS_WORKER=1 -s EXPORT_ALL=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s INITIAL_MEMORY=2GB -s MAXIMUM_MEMORY=4GB -s ALLOW_MEMORY_GROWTH -s FORCE_FILESYSTEM=1 -s EXPORTED_FUNCTIONS=_main -s EXPORTED_RUNTIME_METHODS=callMain -s NO_EXIT_RUNTIME=1"
31 | export EMCC_CFLAGS="-O3 -msimd128 -fno-rtti -DNDEBUG -flto=full -s BUILD_AS_WORKER=1 -s EXPORT_ALL=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s INITIAL_MEMORY=800MB -s MAXIMUM_MEMORY=4GB -s ALLOW_MEMORY_GROWTH -s FORCE_FILESYSTEM=1 -s EXPORTED_FUNCTIONS=_main -s EXPORTED_RUNTIME_METHODS=callMain -s NO_EXIT_RUNTIME=1"
32 | emmake make main -j
33 | cd ../..
34 |
35 | #
36 | # bundle llama-cpp-wasm dist
37 | #
38 | if [ -d $LLAMA_CPP_WASM_DIST_LLAMA_DIR ]; then
39 | rm -rf $LLAMA_CPP_WASM_DIST_LLAMA_DIR
40 | fi
41 |
42 | mkdir -p $LLAMA_CPP_WASM_DIST_LLAMA_DIR
43 | cp -rv src/llama/* $LLAMA_CPP_WASM_DIST_LLAMA_DIR
44 | cp $LLAMA_CPP_BUILD_DIR/bin/main.* $LLAMA_CPP_WASM_DIST_LLAMA_DIR
45 |
46 | rm -rf docs/llama-st
47 | cp -rv $LLAMA_CPP_WASM_DIST_LLAMA_DIR docs/
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | ./build-single-thread.sh
5 | ./build-multi-thread.sh
6 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | llama-cpp-wasm.tangledgroup.com
--------------------------------------------------------------------------------
/docs/example-multi-thread.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | llama-cpp-wasm multithreading
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | WebAssembly (Wasm) Build and Bindings for llama.cpp .
23 |
24 |
25 | This demonstration enables you to run LLM models directly in your browser utilizing JavaScript, WebAssembly, and llama.cpp.
26 |
27 |
28 | Repository: https://github.com/tangledgroup/llama-cpp-wasm
29 |
30 |
31 | When you click Run , model will be first downloaded and cached in browser.
32 |
33 |
34 |
35 |
36 |
37 | Demo
38 |
39 | Model:
40 |
41 |
42 |
43 | tinymistral-248m-sft-v4 q8_0 (265.26 MB)
44 | TinyLlama/TinyLlama-1.1B-Chat-v1.0 Q4_K_M (669 MB)
45 | Qwen/Qwen1.5-1.8B-Chat Q3_K_M (1.02 GB)
46 | stabilityai/stablelm-2-zephyr-1_6b Q4_1 (1.07 GB)
47 | microsoft/phi-1_5 Q4_K_M (918 MB)
48 | microsoft/phi-2 Q3_K_M (1.48 GB)
49 |
50 |
51 | Prompt:
52 |
53 |
54 |
55 | Result:
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 | Loading model...
67 | Loaded model
68 | Generating...
69 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/docs/example-multi-thread.js:
--------------------------------------------------------------------------------
1 | import { LlamaCpp } from "./llama-mt/llama.js";
2 |
3 | let app;
4 | const buttonRun = document.querySelector("#run");
5 | const buttonRunProgressLoadingModel = document.querySelector("#run-progress-loading-model");
6 | const buttonRunProgressLoadedModel = document.querySelector("#run-progress-loaded-model");
7 | const buttonRunProgressGenerating = document.querySelector("#run-progress-generating");
8 | const selectModel = document.querySelector("select#model");
9 | const modelProgress = document.querySelector("#model-progress");
10 | const textareaPrompt = document.querySelector("textarea#prompt");
11 | const textareaResult = document.querySelector("#result");
12 |
13 | const onModelLoaded = () => {
14 | const prompt = textareaPrompt.value;
15 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
16 | buttonRunProgressLoadedModel.removeAttribute("hidden");
17 | console.debug("model: loaded");
18 |
19 | app.run({
20 | prompt: prompt,
21 | ctx_size: 2048,
22 | temp: 0.8,
23 | top_k: 40,
24 | no_display_prompt: true,
25 | });
26 | }
27 |
28 | const onMessageChunk = (text) => {
29 | console.log(text);
30 |
31 | if (buttonRunProgressGenerating.hasAttribute("hidden")) {
32 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
33 | buttonRunProgressLoadedModel.setAttribute("hidden", "hidden");
34 | buttonRunProgressGenerating.removeAttribute("hidden");
35 | }
36 |
37 | // textareaResult.value += text;
38 | textareaResult.innerText += text;
39 | };
40 |
41 | const onComplete = () => {
42 | console.debug("model: completed");
43 | buttonRun.removeAttribute("hidden");
44 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
45 | buttonRunProgressLoadedModel.setAttribute("hidden", "hidden");
46 | buttonRunProgressGenerating.setAttribute("hidden", "hidden");
47 | modelProgress.setAttribute("hidden", "hidden");
48 | };
49 |
50 | buttonRun.addEventListener("click", (e) => {
51 | buttonRun.setAttribute("hidden", "hidden");
52 | buttonRunProgressLoadingModel.removeAttribute("hidden");
53 | modelProgress.removeAttribute("hidden");
54 | // textareaResult.value = "";
55 | textareaResult.innerText = "";
56 |
57 | if (app && app.url == selectModel.value) {
58 | onModelLoaded();
59 | return;
60 | }
61 |
62 | app = new LlamaCpp(
63 | selectModel.value,
64 | onModelLoaded,
65 | onMessageChunk,
66 | onComplete,
67 | );
68 | });
69 |
--------------------------------------------------------------------------------
/docs/example-single-thread.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | llama-cpp-wasm single thread
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 | llama-cpp-wasm 🐢 single thread wasm32
20 |
21 |
22 | WebAssembly (Wasm) Build and Bindings for llama.cpp .
23 |
24 |
25 | This demonstration enables you to run LLM models directly in your browser utilizing JavaScript, WebAssembly, and llama.cpp.
26 |
27 |
28 | Repository: https://github.com/tangledgroup/llama-cpp-wasm
29 |
30 |
31 | When you click Run , model will be first downloaded and cached in browser.
32 |
33 |
34 |
35 |
36 |
37 | Demo
38 |
39 | Model:
40 |
41 |
42 |
43 | tinymistral-248m-sft-v4 q8_0 (265.26 MB)
44 | TinyLlama/TinyLlama-1.1B-Chat-v1.0 Q4_K_M (669 MB)
45 | Qwen/Qwen1.5-1.8B-Chat Q3_K_M (1.02 GB)
46 | stabilityai/stablelm-2-zephyr-1_6b Q4_1 (1.07 GB)
47 | microsoft/phi-1_5 Q4_K_M (918 MB)
48 | microsoft/phi-2 Q3_K_M (1.48 GB)
49 |
50 |
51 | Prompt:
52 |
53 |
54 |
55 | Result:
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 | Loading model...
67 | Loaded model
68 | Generating...
69 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/docs/example-single-thread.js:
--------------------------------------------------------------------------------
1 | import { LlamaCpp } from "./llama-st/llama.js";
2 |
3 | let app;
4 | const buttonRun = document.querySelector("#run");
5 | const buttonRunProgressLoadingModel = document.querySelector("#run-progress-loading-model");
6 | const buttonRunProgressLoadedModel = document.querySelector("#run-progress-loaded-model");
7 | const buttonRunProgressGenerating = document.querySelector("#run-progress-generating");
8 | const selectModel = document.querySelector("select#model");
9 | const modelProgress = document.querySelector("#model-progress");
10 | const textareaPrompt = document.querySelector("textarea#prompt");
11 | const textareaResult = document.querySelector("#result");
12 |
13 | const onModelLoaded = () => {
14 | const prompt = textareaPrompt.value;
15 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
16 | buttonRunProgressLoadedModel.removeAttribute("hidden");
17 | console.debug("model: loaded");
18 |
19 | app.run({
20 | prompt: prompt,
21 | ctx_size: 2048,
22 | temp: 0.8,
23 | top_k: 40,
24 | no_display_prompt: true,
25 | });
26 | }
27 |
28 | const onMessageChunk = (text) => {
29 | console.log(text);
30 |
31 | if (buttonRunProgressGenerating.hasAttribute("hidden")) {
32 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
33 | buttonRunProgressLoadedModel.setAttribute("hidden", "hidden");
34 | buttonRunProgressGenerating.removeAttribute("hidden");
35 | }
36 |
37 | // textareaResult.value += text;
38 | textareaResult.innerText += text;
39 | };
40 |
41 | const onComplete = () => {
42 | console.debug("model: completed");
43 | buttonRun.removeAttribute("hidden");
44 | buttonRunProgressLoadingModel.setAttribute("hidden", "hidden");
45 | buttonRunProgressLoadedModel.setAttribute("hidden", "hidden");
46 | buttonRunProgressGenerating.setAttribute("hidden", "hidden");
47 | modelProgress.setAttribute("hidden", "hidden");
48 | };
49 |
50 | buttonRun.addEventListener("click", (e) => {
51 | buttonRun.setAttribute("hidden", "hidden");
52 | buttonRunProgressLoadingModel.removeAttribute("hidden");
53 | modelProgress.removeAttribute("hidden");
54 | // textareaResult.value = "";
55 | textareaResult.innerText = "";
56 |
57 | if (app && app.url == selectModel.value) {
58 | onModelLoaded();
59 | return;
60 | }
61 |
62 | app = new LlamaCpp(
63 | selectModel.value,
64 | onModelLoaded,
65 | onMessageChunk,
66 | onComplete,
67 | );
68 | });
69 |
--------------------------------------------------------------------------------
/docs/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/favicon.png
--------------------------------------------------------------------------------
/docs/img/js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/img/js.png
--------------------------------------------------------------------------------
/docs/img/llamacpp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/img/llamacpp.png
--------------------------------------------------------------------------------
/docs/img/run-llama-cpp-in-browser-twitter-fs8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/img/run-llama-cpp-in-browser-twitter-fs8.png
--------------------------------------------------------------------------------
/docs/img/tangledgroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/img/tangledgroup.png
--------------------------------------------------------------------------------
/docs/img/wasm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/img/wasm.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | llama-cpp-wasm
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | WebAssembly (Wasm) Build and Bindings for llama.cpp .
23 |
24 |
25 | This demonstration enables you to run LLM models directly in your browser utilizing JavaScript, WebAssembly, and llama.cpp.
26 |
27 |
28 | Repository: https://github.com/tangledgroup/llama-cpp-wasm
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | In-Browser Demos
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 | Ecosystem
52 |
53 |
54 |
55 |
62 |
63 |
70 |
71 |
78 |
79 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/docs/llama-mt/actions.js:
--------------------------------------------------------------------------------
1 | export const action = {
2 | LOAD: 0,
3 | INITIALIZED: 1,
4 | RUN_MAIN: 2,
5 | WRITE_RESULT: 3,
6 | RUN_COMPLETED: 4,
7 | ERROR: 5
8 | };
--------------------------------------------------------------------------------
/docs/llama-mt/llama.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 |
3 | class LlamaCpp {
4 | // callback have to be defined before load_worker
5 | constructor(url, init_callback, write_result_callback, on_complete_callback) {
6 | this.url = url;
7 | this.init_callback = init_callback;
8 | this.write_result_callback = write_result_callback;
9 | this.on_complete_callback = on_complete_callback;
10 | this.loadWorker();
11 | }
12 |
13 | loadWorker() {
14 | this.worker = new Worker(
15 | new URL("./main-worker.js", import.meta.url),
16 | {type: "module"}
17 | );
18 |
19 | this.worker.onmessage = (event) => {
20 | switch (event.data.event) {
21 | case action.INITIALIZED:
22 | // Load Model
23 | if (this.init_callback) {
24 | this.init_callback();
25 | }
26 |
27 | break;
28 | case action.WRITE_RESULT:
29 | // Capture result
30 | if (this.write_result_callback) {
31 | this.write_result_callback(event.data.text);
32 | }
33 |
34 | break;
35 | case action.RUN_COMPLETED:
36 | // Execution Completed
37 | if (this.on_complete_callback) {
38 | this.on_complete_callback();
39 | }
40 |
41 | break;
42 | }
43 | };
44 |
45 | this.worker.postMessage({
46 | event: action.LOAD,
47 | url: this.url,
48 | });
49 | }
50 |
51 | run({
52 | prompt,
53 | chatml=false,
54 | n_predict=-2,
55 | ctx_size=2048,
56 | batch_size=512,
57 | temp=0.8,
58 | n_gpu_layers=0,
59 | top_k=40,
60 | top_p=0.9,
61 | no_display_prompt=true,
62 | }={}) {
63 | this.worker.postMessage({
64 | event: action.RUN_MAIN,
65 | prompt,
66 | chatml,
67 | n_predict,
68 | ctx_size,
69 | batch_size,
70 | temp,
71 | n_gpu_layers,
72 | top_k,
73 | top_p,
74 | no_display_prompt,
75 | });
76 | }
77 | }
78 |
79 | export { LlamaCpp };
--------------------------------------------------------------------------------
/docs/llama-mt/main-worker.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 | import { loadBinaryResource } from "./utility.js";
3 | import Module from "./main.js";
4 |
5 | // WASM Module
6 | let module;
7 |
8 | // hard-coded filepath for loaded model in vfs
9 | const model_path = "/models/model.bin";
10 |
11 | // Function to send model line result
12 | const print = (text) => {
13 | postMessage({
14 | event: action.WRITE_RESULT,
15 | text: text,
16 | });
17 | };
18 |
19 | // Function to initialize worker
20 | // and download model file
21 | const decoder = new TextDecoder('utf-8');
22 | const punctuationBytes = [33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126];
23 | const whitespaceBytes = [32, 9, 10, 13, 11, 12];
24 | const splitBytes = [...punctuationBytes, ...whitespaceBytes];
25 | const stdoutBuffer = [];
26 |
27 | const stdin = () => {};
28 |
29 | const stdout = (c) => {
30 | stdoutBuffer.push(c);
31 |
32 | if (splitBytes.indexOf(c) == -1) {
33 | return;
34 | }
35 |
36 | const text = decoder.decode(new Uint8Array(stdoutBuffer));
37 | stdoutBuffer.splice(0, stdoutBuffer.length);
38 | print(text);
39 | };
40 |
41 | const stderr = () => {};
42 |
43 | const initWorker = async (modelPath) => {
44 | const emscrModule = {
45 | noInitialRun: true,
46 | preInit: [() => {
47 | emscrModule.TTY.register(emscrModule.FS.makedev(5, 0), {
48 | get_char: tty => stdin(tty),
49 | put_char: (tty, val) => { tty.output.push(val); stdout(val); },
50 | flush: tty => tty.output = [],
51 | fsync: tty => console.log("fsynced stdout (EmscriptenRunnable does nothing in this case)")
52 | });
53 |
54 | emscrModule.TTY.register(emscrModule.FS.makedev(6, 0), {
55 | get_char: tty => stdin(tty),
56 | put_char: (tty, val) => { tty.output.push(val); stderr(val); },
57 | flush: tty => tty.output = [],
58 | fsync: tty => console.log("fsynced stderr (EmscriptenRunnable does nothing in this case)")
59 | });
60 | }],
61 | };
62 |
63 | module = await Module(emscrModule);
64 |
65 | const initCallback = (bytes) => {
66 | // create vfs folder for storing model bins
67 | module['FS_createPath']("/", "models", true, true);
68 |
69 | // load model
70 | module['FS_createDataFile']('/models', 'model.bin', bytes, true, true, true);
71 |
72 | // update callback action to worker main thread
73 | postMessage({
74 | event: action.INITIALIZED
75 | });
76 | }
77 |
78 | loadBinaryResource(modelPath, initCallback);
79 | }
80 |
81 | const run_main = (
82 | prompt,
83 | chatml,
84 | n_predict,
85 | ctx_size,
86 | batch_size,
87 | temp,
88 | n_gpu_layers,
89 | top_k,
90 | top_p,
91 | no_display_prompt
92 | ) => {
93 | const args = [
94 | "--model", model_path,
95 | "--n-predict", n_predict.toString(),
96 | "--ctx-size", ctx_size.toString(),
97 | "--temp", temp.toString(),
98 | "--top_k", top_k.toString(),
99 | "--top_p", top_p.toString(),
100 | // "--no-mmap",
101 | "--simple-io",
102 | "--log-disable",
103 | "--prompt", prompt.toString(),
104 | ];
105 |
106 | if (!!globalThis.SharedArrayBuffer) {
107 | args.push("--threads");
108 | args.push((navigator.hardwareConcurrency).toString());
109 | }
110 |
111 | if (chatml) {
112 | args.push("--chatml");
113 | }
114 |
115 | if (no_display_prompt) {
116 | args.push("--no-display-prompt");
117 | }
118 |
119 | module['callMain'](args);
120 |
121 | postMessage({
122 | event: action.RUN_COMPLETED
123 | });
124 | }
125 |
126 | // Worker Events
127 | self.addEventListener('message', (e) => {
128 | switch (e.data.event) {
129 | case action.LOAD:
130 | // load event
131 | initWorker(e.data.url);
132 | break;
133 | case action.RUN_MAIN:
134 | // run main
135 | run_main(
136 | e.data.prompt,
137 | e.data.chatml,
138 | e.data.n_predict,
139 | e.data.ctx_size,
140 | e.data.batch_size,
141 | e.data.temp,
142 | e.data.n_gpu_layers,
143 | e.data.top_k,
144 | e.data.top_p,
145 | e.data.no_display_prompt,
146 | );
147 |
148 | break;
149 | }
150 | }, false);
151 |
--------------------------------------------------------------------------------
/docs/llama-mt/main.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/llama-mt/main.wasm
--------------------------------------------------------------------------------
/docs/llama-mt/main.worker.mjs:
--------------------------------------------------------------------------------
1 | "use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){const{createRequire:createRequire}=await import("module");var require=createRequire(import.meta.url);var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");var vm=require("vm");Object.assign(global,{self:global,require:require,Module:Module,location:{href:typeof __filename!=="undefined"?__filename:import.meta.url},Worker:nodeWorkerThreads.Worker,importScripts:f=>vm.runInThisContext(fs.readFileSync(f,"utf8"),{filename:f}),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./main.js")).then(exports=>exports.default(Module))}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){Module["__emscripten_thread_crashed"]?.();throw ex}}self.onmessage=handleMessage;
2 |
--------------------------------------------------------------------------------
/docs/llama-mt/utility.js:
--------------------------------------------------------------------------------
1 | const cacheName = "llama-cpp-wasm-cache";
2 |
3 | export async function loadBinaryResource(url, callback) {
4 | let cache = null, window = self;
5 |
6 | // Try to find if the model data is cached in Web Worker memory.
7 | if (typeof window === "undefined") {
8 | console.debug("`window` is not defined");
9 | } else if (window && window.caches) {
10 | cache = await window.caches.open(cacheName);
11 | const cachedResponse = await cache.match(url);
12 |
13 | if (cachedResponse) {
14 | const data = await cachedResponse.arrayBuffer();
15 | const byteArray = new Uint8Array(data);
16 | callback(byteArray);
17 | return;
18 | }
19 | }
20 |
21 |
22 | // Download model and store in cache
23 | const req = new XMLHttpRequest();
24 | req.open("GET", url, true);
25 | req.responseType = "arraybuffer";
26 |
27 | req.onload = async (_) => {
28 | const arrayBuffer = req.response; // Note: not req.responseText
29 |
30 | if (arrayBuffer) {
31 | const byteArray = new Uint8Array(arrayBuffer);
32 |
33 | if (cache) {
34 | await cache.put(url, new Response(arrayBuffer))
35 | };
36 |
37 | callback(byteArray);
38 | }
39 | };
40 |
41 | req.send(null);
42 | }
43 |
--------------------------------------------------------------------------------
/docs/llama-st/actions.js:
--------------------------------------------------------------------------------
1 | export const action = {
2 | LOAD: 0,
3 | INITIALIZED: 1,
4 | RUN_MAIN: 2,
5 | WRITE_RESULT: 3,
6 | RUN_COMPLETED: 4,
7 | ERROR: 5
8 | };
--------------------------------------------------------------------------------
/docs/llama-st/llama.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 |
3 | class LlamaCpp {
4 | // callback have to be defined before load_worker
5 | constructor(url, init_callback, write_result_callback, on_complete_callback) {
6 | this.url = url;
7 | this.init_callback = init_callback;
8 | this.write_result_callback = write_result_callback;
9 | this.on_complete_callback = on_complete_callback;
10 | this.loadWorker();
11 | }
12 |
13 | loadWorker() {
14 | this.worker = new Worker(
15 | new URL("./main-worker.js", import.meta.url),
16 | {type: "module"}
17 | );
18 |
19 | this.worker.onmessage = (event) => {
20 | switch (event.data.event) {
21 | case action.INITIALIZED:
22 | // Load Model
23 | if (this.init_callback) {
24 | this.init_callback();
25 | }
26 |
27 | break;
28 | case action.WRITE_RESULT:
29 | // Capture result
30 | if (this.write_result_callback) {
31 | this.write_result_callback(event.data.text);
32 | }
33 |
34 | break;
35 | case action.RUN_COMPLETED:
36 | // Execution Completed
37 | if (this.on_complete_callback) {
38 | this.on_complete_callback();
39 | }
40 |
41 | break;
42 | }
43 | };
44 |
45 | this.worker.postMessage({
46 | event: action.LOAD,
47 | url: this.url,
48 | });
49 | }
50 |
51 | run({
52 | prompt,
53 | chatml=false,
54 | n_predict=-2,
55 | ctx_size=2048,
56 | batch_size=512,
57 | temp=0.8,
58 | n_gpu_layers=0,
59 | top_k=40,
60 | top_p=0.9,
61 | no_display_prompt=true,
62 | }={}) {
63 | this.worker.postMessage({
64 | event: action.RUN_MAIN,
65 | prompt,
66 | chatml,
67 | n_predict,
68 | ctx_size,
69 | batch_size,
70 | temp,
71 | n_gpu_layers,
72 | top_k,
73 | top_p,
74 | no_display_prompt,
75 | });
76 | }
77 | }
78 |
79 | export { LlamaCpp };
--------------------------------------------------------------------------------
/docs/llama-st/main-worker.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 | import { loadBinaryResource } from "./utility.js";
3 | import Module from "./main.js";
4 |
5 | // WASM Module
6 | let module;
7 |
8 | // hard-coded filepath for loaded model in vfs
9 | const model_path = "/models/model.bin";
10 |
11 | // Function to send model line result
12 | const print = (text) => {
13 | postMessage({
14 | event: action.WRITE_RESULT,
15 | text: text,
16 | });
17 | };
18 |
19 | // Function to initialize worker
20 | // and download model file
21 | const decoder = new TextDecoder('utf-8');
22 | const punctuationBytes = [33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126];
23 | const whitespaceBytes = [32, 9, 10, 13, 11, 12];
24 | const splitBytes = [...punctuationBytes, ...whitespaceBytes];
25 | const stdoutBuffer = [];
26 |
27 | const stdin = () => {};
28 |
29 | const stdout = (c) => {
30 | stdoutBuffer.push(c);
31 |
32 | if (splitBytes.indexOf(c) == -1) {
33 | return;
34 | }
35 |
36 | const text = decoder.decode(new Uint8Array(stdoutBuffer));
37 | stdoutBuffer.splice(0, stdoutBuffer.length);
38 | print(text);
39 | };
40 |
41 | const stderr = () => {};
42 |
43 | const initWorker = async (modelPath) => {
44 | const emscrModule = {
45 | noInitialRun: true,
46 | preInit: [() => {
47 | emscrModule.TTY.register(emscrModule.FS.makedev(5, 0), {
48 | get_char: tty => stdin(tty),
49 | put_char: (tty, val) => { tty.output.push(val); stdout(val); },
50 | flush: tty => tty.output = [],
51 | fsync: tty => console.log("fsynced stdout (EmscriptenRunnable does nothing in this case)")
52 | });
53 |
54 | emscrModule.TTY.register(emscrModule.FS.makedev(6, 0), {
55 | get_char: tty => stdin(tty),
56 | put_char: (tty, val) => { tty.output.push(val); stderr(val); },
57 | flush: tty => tty.output = [],
58 | fsync: tty => console.log("fsynced stderr (EmscriptenRunnable does nothing in this case)")
59 | });
60 | }],
61 | };
62 |
63 | module = await Module(emscrModule);
64 |
65 | const initCallback = (bytes) => {
66 | // create vfs folder for storing model bins
67 | module['FS_createPath']("/", "models", true, true);
68 |
69 | // load model
70 | module['FS_createDataFile']('/models', 'model.bin', bytes, true, true, true);
71 |
72 | // update callback action to worker main thread
73 | postMessage({
74 | event: action.INITIALIZED
75 | });
76 | }
77 |
78 | loadBinaryResource(modelPath, initCallback);
79 | }
80 |
81 | const run_main = (
82 | prompt,
83 | chatml,
84 | n_predict,
85 | ctx_size,
86 | batch_size,
87 | temp,
88 | n_gpu_layers,
89 | top_k,
90 | top_p,
91 | no_display_prompt
92 | ) => {
93 | const args = [
94 | "--model", model_path,
95 | "--n-predict", n_predict.toString(),
96 | "--ctx-size", ctx_size.toString(),
97 | "--temp", temp.toString(),
98 | "--top_k", top_k.toString(),
99 | "--top_p", top_p.toString(),
100 | // "--no-mmap",
101 | "--simple-io",
102 | "--log-disable",
103 | "--prompt", prompt.toString(),
104 | ];
105 |
106 | if (!!globalThis.SharedArrayBuffer) {
107 | args.push("--threads");
108 | args.push((navigator.hardwareConcurrency).toString());
109 | }
110 |
111 | if (chatml) {
112 | args.push("--chatml");
113 | }
114 |
115 | if (no_display_prompt) {
116 | args.push("--no-display-prompt");
117 | }
118 |
119 | module['callMain'](args);
120 |
121 | postMessage({
122 | event: action.RUN_COMPLETED
123 | });
124 | }
125 |
126 | // Worker Events
127 | self.addEventListener('message', (e) => {
128 | switch (e.data.event) {
129 | case action.LOAD:
130 | // load event
131 | initWorker(e.data.url);
132 | break;
133 | case action.RUN_MAIN:
134 | // run main
135 | run_main(
136 | e.data.prompt,
137 | e.data.chatml,
138 | e.data.n_predict,
139 | e.data.ctx_size,
140 | e.data.batch_size,
141 | e.data.temp,
142 | e.data.n_gpu_layers,
143 | e.data.top_k,
144 | e.data.top_p,
145 | e.data.no_display_prompt,
146 | );
147 |
148 | break;
149 | }
150 | }, false);
151 |
--------------------------------------------------------------------------------
/docs/llama-st/main.js:
--------------------------------------------------------------------------------
1 |
2 | var Module = (() => {
3 | var _scriptDir = import.meta.url;
4 |
5 | return (
6 | async function(moduleArg = {}) {
7 |
8 | var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){const{createRequire:createRequire}=await import("module");var require=createRequire(import.meta.url);var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=require("url").fileURLToPath(new URL("./",import.meta.url))}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};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=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");var wasmBinaryFile;if(Module["locateFile"]){wasmBinaryFile="main.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}}else{wasmBinaryFile=new URL("main.wasm",import.meta.url).href}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"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw`failed to load wasm binary file at '${binaryFile}'`}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}else if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=applySignatureConversions(wasmExports);wasmMemory=wasmExports["B"];updateMemoryViews();addOnInit(wasmExports["C"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}Module["ExitStatus"]=ExitStatus;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};Module["callRuntimeCallbacks"]=callRuntimeCallbacks;function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr>>>0>>>0];case"i8":return HEAP8[ptr>>>0>>>0];case"i16":return HEAP16[ptr>>>1>>>0];case"i32":return HEAP32[ptr>>>2>>>0];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>>2>>>0];case"double":return HEAPF64[ptr>>>3>>>0];case"*":return HEAPU32[ptr>>>2>>>0];default:abort(`invalid type for getValue: ${type}`)}}Module["getValue"]=getValue;var noExitRuntime=Module["noExitRuntime"]||true;Module["noExitRuntime"]=noExitRuntime;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>>0>>>0]=value;break;case"i8":HEAP8[ptr>>>0>>>0]=value;break;case"i16":HEAP16[ptr>>>1>>>0]=value;break;case"i32":HEAP32[ptr>>>2>>>0]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>>2>>>0]=value;break;case"double":HEAPF64[ptr>>>3>>>0]=value;break;case"*":HEAPU32[ptr>>>2>>>0]=value;break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue"]=setValue;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0>>>0]!=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>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>>2>>>0]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}Module["ExceptionInfo"]=ExceptionInfo;var exceptionLast=0;Module["exceptionLast"]=exceptionLast;var uncaughtExceptionCount=0;Module["uncaughtExceptionCount"]=uncaughtExceptionCount;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}Module["___cxa_throw"]=___cxa_throw;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.substr(-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.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};Module["PATH"]=PATH;var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};Module["initRandomFill"]=initRandomFill;var randomFill=view=>(randomFill=initRandomFill())(view);Module["randomFill"]=randomFill;var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[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).substr(1);to=PATH_FS.resolve(to).substr(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{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};Module["UTF8ArrayToString"]=UTF8ArrayToString;var FS_stdin_getChar_buffer=[];Module["FS_stdin_getChar_buffer"]=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};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};Module["stringToUTF8Array"]=stringToUTF8Array;function 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}Module["intArrayFromString"]=intArrayFromString;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)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};Module["FS_stdin_getChar"]=FS_stdin_getChar;var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops: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,0));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,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};Module["TTY"]=TTY;var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};Module["zeroMemory"]=zeroMemory;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;Module["alignMemory"]=alignMemory;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};Module["mmapAlloc"]=mmapAlloc;var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,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,allocate:MEMFS.stream_ops.allocate,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=null}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.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){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.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=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.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},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);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}return{ptr:ptr,allocated:allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};Module["MEMFS"]=MEMFS;var asyncLoad=(url,onload,onerror,noRunDep)=>{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};Module["asyncLoad"]=asyncLoad;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};Module["FS_createDataFile"]=FS_createDataFile;var preloadPlugins=Module["preloadPlugins"]||[];Module["preloadPlugins"]=preloadPlugins;var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};Module["FS_createPreloadedFile"]=FS_createPreloadedFile;var FS_modeStringToFlags=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};Module["FS_modeStringToFlags"]=FS_modeStringToFlags;var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};Module["FS_getMode"]=FS_getMode;var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno}},genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;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}else if(perms.includes("w")&&!(node.mode&146)){return 2}else 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){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}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},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){if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val}},isRead:{get(){return(this.flags&2097155)!==1}},isWrite:{get(){return(this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val}},position:{get(){return this.shared.position},set(val){this.shared.position=val}}})}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},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.apply(check,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)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},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:type,opts:opts,mountpoint: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);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];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||name==="."||name===".."){throw new FS.ErrnoError(28)}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)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,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"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;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"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}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});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){randomLeft=randomFill(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",16384|511,73);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}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}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(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;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]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("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)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("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))throw new Error("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")throw new Error("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};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url: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={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});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:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};Module["UTF8ToString"]=UTF8ToString;var SYSCALLS={DEFAULT_POLLMASK:5,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 PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>>2>>>0]=tempI64[0],HEAP32[buf+28>>>2>>>0]=tempI64[1];HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>>2>>>0]=tempI64[0],HEAP32[buf+44>>>2>>>0]=tempI64[1];HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>>2>>>0]=tempI64[0],HEAP32[buf+60>>>2>>>0]=tempI64[1];HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>>2>>>0]=tempI64[0],HEAP32[buf+76>>>2>>>0]=tempI64[1];HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>>2>>>0]=tempI64[0],HEAP32[buf+92>>>2>>>0]=tempI64[1];return 0},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.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get(){var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};Module["SYSCALLS"]=SYSCALLS;function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.getp();var offset=0;HEAP16[arg+offset>>>1>>>0]=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}}Module["___syscall_fcntl64"]=___syscall_fcntl64;function ___syscall_fstat64(fd,buf){buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fstat64"]=___syscall_fstat64;function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;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=SYSCALLS.getp();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0>>>0]=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=SYSCALLS.getp();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.getp();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.getp();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=SYSCALLS.getp();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=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}}Module["___syscall_ioctl"]=___syscall_ioctl;function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_lstat64"]=___syscall_lstat64;function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_mkdirat"]=___syscall_mkdirat;function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_newfstatat"]=___syscall_newfstatat;function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_openat"]=___syscall_openat;function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_stat64"]=___syscall_stat64;var nowIsMonotonic=1;Module["nowIsMonotonic"]=nowIsMonotonic;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;Module["__emscripten_get_now_is_monotonic"]=__emscripten_get_now_is_monotonic;var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);Module["isLeapYear"]=isLeapYear;var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];Module["MONTH_DAYS_LEAP_CUMULATIVE"]=MONTH_DAYS_LEAP_CUMULATIVE;var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];Module["MONTH_DAYS_REGULAR_CUMULATIVE"]=MONTH_DAYS_REGULAR_CUMULATIVE;var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};Module["ydayFromDate"]=ydayFromDate;function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}Module["__localtime_js"]=__localtime_js;function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){len>>>=0;var offset=convertI32PairToI53Checked(offset_low,offset_high);allocated>>>=0;addr>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>>2>>>0]=res.allocated;HEAPU32[addr>>>2>>>0]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__mmap_js"]=__mmap_js;function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){addr>>>=0;len>>>=0;var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}FS.munmap(stream)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__munmap_js"]=__munmap_js;var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};Module["stringToNewUTF8"]=stringToNewUTF8;function __tzset_js(timezone,daylight,tzname){timezone>>>=0;daylight>>>=0;tzname>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=stringToNewUTF8(winterName);var summerNamePtr=stringToNewUTF8(summerName);if(summerOffset>>2>>>0]=winterNamePtr;HEAPU32[tzname+4>>>2>>>0]=summerNamePtr}else{HEAPU32[tzname>>>2>>>0]=summerNamePtr;HEAPU32[tzname+4>>>2>>>0]=winterNamePtr}}Module["__tzset_js"]=__tzset_js;var _abort=()=>{abort("")};Module["_abort"]=_abort;var _emscripten_date_now=()=>Date.now();Module["_emscripten_date_now"]=_emscripten_date_now;var getHeapMax=()=>4294901760;Module["getHeapMax"]=getHeapMax;function _emscripten_get_heap_max(){return getHeapMax()}Module["_emscripten_get_heap_max"]=_emscripten_get_heap_max;var _emscripten_get_now;_emscripten_get_now=()=>performance.now();Module["_emscripten_get_now"]=_emscripten_get_now;function _emscripten_memcpy_js(dest,src,num){dest>>>=0;src>>>=0;num>>>=0;return HEAPU8.copyWithin(dest>>>0,src>>>0,src+num>>>0)}Module["_emscripten_memcpy_js"]=_emscripten_memcpy_js;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};Module["growMemory"]=growMemory;function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;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,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}Module["_emscripten_resize_heap"]=_emscripten_resize_heap;var ENV={};Module["ENV"]=ENV;var getExecutableName=()=>thisProgram||"./this.program";Module["getExecutableName"]=getExecutableName;var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"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};Module["getEnvStrings"]=getEnvStrings;var stringToAscii=(str,buffer)=>{for(var i=0;i>>0>>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0>>>0]=0};Module["stringToAscii"]=stringToAscii;var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};Module["_environ_get"]=_environ_get;var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};Module["_environ_sizes_get"]=_environ_sizes_get;var runtimeKeepaliveCounter=0;Module["runtimeKeepaliveCounter"]=runtimeKeepaliveCounter;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;Module["keepRuntimeAlive"]=keepRuntimeAlive;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};Module["_proc_exit"]=_proc_exit;var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};Module["exitJS"]=exitJS;var _exit=exitJS;Module["_exit"]=_exit;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}}Module["_fd_close"]=_fd_close;var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_read"]=_fd_read;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>>2>>>0]=tempI64[0],HEAP32[newOffset+4>>>2>>>0]=tempI64[1];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}}Module["_fd_seek"]=_fd_seek;var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret};Module["doWritev"]=doWritev;function _fd_write(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_write"]=_fd_write;var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};Module["arraySum"]=arraySum;var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_LEAP"]=MONTH_DAYS_LEAP;var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_REGULAR"]=MONTH_DAYS_REGULAR;var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};Module["addDays"]=addDays;var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};Module["writeArrayToMemory"]=writeArrayToMemory;function _strftime(s,maxsize,format,tm){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;var tm_zone=HEAPU32[tm+40>>>2>>>0];var date={tm_sec:HEAP32[tm>>>2>>>0],tm_min:HEAP32[tm+4>>>2>>>0],tm_hour:HEAP32[tm+8>>>2>>>0],tm_mday:HEAP32[tm+12>>>2>>>0],tm_mon:HEAP32[tm+16>>>2>>>0],tm_year:HEAP32[tm+20>>>2>>>0],tm_wday:HEAP32[tm+24>>>2>>>0],tm_yday:HEAP32[tm+28>>>2>>>0],tm_isdst:HEAP32[tm+32>>>2>>>0],tm_gmtoff:HEAP32[tm+36>>>2>>>0],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":getWeekBasedYear,"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}Module["_strftime"]=_strftime;function _strftime_l(s,maxsize,format,tm,loc){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;loc>>>=0;return _strftime(s,maxsize,format,tm)}Module["_strftime_l"]=_strftime_l;var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};Module["handleException"]=handleException;var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};Module["stringToUTF8OnStack"]=stringToUTF8OnStack;var FS_unlink=path=>FS.unlink(path);Module["FS_unlink"]=FS_unlink;var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;var wasmImports={b:___cxa_throw,e:___syscall_fcntl64,d:___syscall_ioctl,v:___syscall_mkdirat,i:___syscall_openat,u:___syscall_stat64,j:__emscripten_get_now_is_monotonic,o:__localtime_js,m:__mmap_js,n:__munmap_js,s:__tzset_js,a:_abort,f:_emscripten_date_now,t:_emscripten_get_heap_max,c:_emscripten_get_now,y:_emscripten_memcpy_js,r:_emscripten_resize_heap,w:_environ_get,x:_environ_sizes_get,g:_exit,h:_fd_close,A:_fd_read,p:_fd_seek,z:_fd_write,k:_proc_exit,l:_strftime,q:_strftime_l};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["C"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["D"])(a0,a1);var _free=a0=>(_free=wasmExports["E"])(a0);var _malloc=a0=>(_malloc=wasmExports["F"])(a0);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["H"])(a0,a1);var setTempRet0=a0=>(setTempRet0=wasmExports["I"])(a0);var stackSave=()=>(stackSave=wasmExports["J"])();var stackRestore=a0=>(stackRestore=wasmExports["K"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["L"])(a0);var ___cxa_increment_exception_refcount=a0=>(___cxa_increment_exception_refcount=wasmExports["M"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["N"])(a0);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["O"])(a0,a1,a2,a3,a4);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["P"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["Q"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["R"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["S"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_ppp=f=>(a0,a1)=>f(a0,a1)>>>0;var makeWrapper_p=f=>()=>f()>>>0;wasmExports["F"]=makeWrapper_pp(wasmExports["F"]);wasmExports["H"]=makeWrapper_ppp(wasmExports["H"]);wasmExports["J"]=makeWrapper_p(wasmExports["J"]);wasmExports["L"]=makeWrapper_pp(wasmExports["L"]);return wasmExports}Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createPath"]=FS.createPath;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["callMain"]=callMain;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_unlink"]=FS.unlink;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();var workerResponded=false,workerCallbackId=-1;(function(){var messageBuffer=null,buffer=0,bufferSize=0;function flushMessages(){if(!messageBuffer)return;if(runtimeInitialized){var temp=messageBuffer;messageBuffer=null;temp.forEach(function(message){onmessage(message)})}}function messageResender(){flushMessages();if(messageBuffer){setTimeout(messageResender,100)}}onmessage=msg=>{if(!runtimeInitialized){if(!messageBuffer){messageBuffer=[];setTimeout(messageResender,100)}messageBuffer.push(msg);return}flushMessages();var func=Module["_"+msg.data["funcName"]];if(!func)throw"invalid worker function to call: "+msg.data["funcName"];var data=msg.data["data"];if(data){if(!data.byteLength)data=new Uint8Array(data);if(!buffer||bufferSize>>0)}workerResponded=false;workerCallbackId=msg.data["callbackId"];if(data){func(buffer,data.length)}else{func(0,0)}}})();
9 |
10 |
11 | return moduleArg.ready
12 | }
13 | );
14 | })();
15 | export default Module;
--------------------------------------------------------------------------------
/docs/llama-st/main.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangledgroup/llama-cpp-wasm/c1fa952e9d6be14bbc3dfe2668aaa72ac83531ba/docs/llama-st/main.wasm
--------------------------------------------------------------------------------
/docs/llama-st/utility.js:
--------------------------------------------------------------------------------
1 | const cacheName = "llama-cpp-wasm-cache";
2 |
3 | export async function loadBinaryResource(url, callback) {
4 | let cache = null, window = self;
5 |
6 | // Try to find if the model data is cached in Web Worker memory.
7 | if (typeof window === "undefined") {
8 | console.debug("`window` is not defined");
9 | } else if (window && window.caches) {
10 | cache = await window.caches.open(cacheName);
11 | const cachedResponse = await cache.match(url);
12 |
13 | if (cachedResponse) {
14 | const data = await cachedResponse.arrayBuffer();
15 | const byteArray = new Uint8Array(data);
16 | callback(byteArray);
17 | return;
18 | }
19 | }
20 |
21 |
22 | // Download model and store in cache
23 | const req = new XMLHttpRequest();
24 | req.open("GET", url, true);
25 | req.responseType = "arraybuffer";
26 |
27 | req.onload = async (_) => {
28 | const arrayBuffer = req.response; // Note: not req.responseText
29 |
30 | if (arrayBuffer) {
31 | const byteArray = new Uint8Array(arrayBuffer);
32 |
33 | if (cache) {
34 | await cache.put(url, new Response(arrayBuffer))
35 | };
36 |
37 | callback(byteArray);
38 | }
39 | };
40 |
41 | req.send(null);
42 | }
43 |
--------------------------------------------------------------------------------
/docs/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const https = require('https');
3 | const fs = require('fs');
4 | const app = express();
5 |
6 | const host = '0.0.0.0';
7 | const port = 8080;
8 |
9 | // Path to your certificate and key files
10 | const privateKey = fs.readFileSync('key.pem', 'utf8');
11 | const certificate = fs.readFileSync('cert.pem', 'utf8');
12 |
13 | const credentials = { key: privateKey, cert: certificate };
14 |
15 | // Middleware to set required headers for SharedArrayBuffer access
16 | app.use((req, res, next) => {
17 | res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
18 | res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
19 | next();
20 | });
21 |
22 | // Serve static files from the 'public' directory
23 | app.use(express.static('.'));
24 |
25 | // Create an HTTPS server with your custom certificate and key
26 | const httpsServer = https.createServer(credentials, app);
27 |
28 | httpsServer.listen(port, host, () => {
29 | console.log(`HTTPS server listening at https://${host}:${port}`);
30 | });
31 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "llama-cpp-wasm",
3 | "version": "0.1.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "llama-cpp-wasm",
9 | "version": "0.1.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "express": "^4.18.2"
13 | }
14 | },
15 | "node_modules/accepts": {
16 | "version": "1.3.8",
17 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
18 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
19 | "dependencies": {
20 | "mime-types": "~2.1.34",
21 | "negotiator": "0.6.3"
22 | },
23 | "engines": {
24 | "node": ">= 0.6"
25 | }
26 | },
27 | "node_modules/array-flatten": {
28 | "version": "1.1.1",
29 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
30 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
31 | },
32 | "node_modules/body-parser": {
33 | "version": "1.20.1",
34 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
35 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
36 | "dependencies": {
37 | "bytes": "3.1.2",
38 | "content-type": "~1.0.4",
39 | "debug": "2.6.9",
40 | "depd": "2.0.0",
41 | "destroy": "1.2.0",
42 | "http-errors": "2.0.0",
43 | "iconv-lite": "0.4.24",
44 | "on-finished": "2.4.1",
45 | "qs": "6.11.0",
46 | "raw-body": "2.5.1",
47 | "type-is": "~1.6.18",
48 | "unpipe": "1.0.0"
49 | },
50 | "engines": {
51 | "node": ">= 0.8",
52 | "npm": "1.2.8000 || >= 1.4.16"
53 | }
54 | },
55 | "node_modules/bytes": {
56 | "version": "3.1.2",
57 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
58 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
59 | "engines": {
60 | "node": ">= 0.8"
61 | }
62 | },
63 | "node_modules/call-bind": {
64 | "version": "1.0.6",
65 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz",
66 | "integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==",
67 | "dependencies": {
68 | "es-errors": "^1.3.0",
69 | "function-bind": "^1.1.2",
70 | "get-intrinsic": "^1.2.3",
71 | "set-function-length": "^1.2.0"
72 | },
73 | "engines": {
74 | "node": ">= 0.4"
75 | },
76 | "funding": {
77 | "url": "https://github.com/sponsors/ljharb"
78 | }
79 | },
80 | "node_modules/content-disposition": {
81 | "version": "0.5.4",
82 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
83 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
84 | "dependencies": {
85 | "safe-buffer": "5.2.1"
86 | },
87 | "engines": {
88 | "node": ">= 0.6"
89 | }
90 | },
91 | "node_modules/content-type": {
92 | "version": "1.0.5",
93 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
94 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
95 | "engines": {
96 | "node": ">= 0.6"
97 | }
98 | },
99 | "node_modules/cookie": {
100 | "version": "0.5.0",
101 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
102 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
103 | "engines": {
104 | "node": ">= 0.6"
105 | }
106 | },
107 | "node_modules/cookie-signature": {
108 | "version": "1.0.6",
109 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
110 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
111 | },
112 | "node_modules/debug": {
113 | "version": "2.6.9",
114 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
115 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
116 | "dependencies": {
117 | "ms": "2.0.0"
118 | }
119 | },
120 | "node_modules/define-data-property": {
121 | "version": "1.1.2",
122 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz",
123 | "integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==",
124 | "dependencies": {
125 | "es-errors": "^1.3.0",
126 | "get-intrinsic": "^1.2.2",
127 | "gopd": "^1.0.1",
128 | "has-property-descriptors": "^1.0.1"
129 | },
130 | "engines": {
131 | "node": ">= 0.4"
132 | }
133 | },
134 | "node_modules/depd": {
135 | "version": "2.0.0",
136 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
137 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
138 | "engines": {
139 | "node": ">= 0.8"
140 | }
141 | },
142 | "node_modules/destroy": {
143 | "version": "1.2.0",
144 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
145 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
146 | "engines": {
147 | "node": ">= 0.8",
148 | "npm": "1.2.8000 || >= 1.4.16"
149 | }
150 | },
151 | "node_modules/ee-first": {
152 | "version": "1.1.1",
153 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
154 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
155 | },
156 | "node_modules/encodeurl": {
157 | "version": "1.0.2",
158 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
159 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
160 | "engines": {
161 | "node": ">= 0.8"
162 | }
163 | },
164 | "node_modules/es-errors": {
165 | "version": "1.3.0",
166 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
167 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
168 | "engines": {
169 | "node": ">= 0.4"
170 | }
171 | },
172 | "node_modules/escape-html": {
173 | "version": "1.0.3",
174 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
175 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
176 | },
177 | "node_modules/etag": {
178 | "version": "1.8.1",
179 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
180 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
181 | "engines": {
182 | "node": ">= 0.6"
183 | }
184 | },
185 | "node_modules/express": {
186 | "version": "4.18.2",
187 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
188 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
189 | "dependencies": {
190 | "accepts": "~1.3.8",
191 | "array-flatten": "1.1.1",
192 | "body-parser": "1.20.1",
193 | "content-disposition": "0.5.4",
194 | "content-type": "~1.0.4",
195 | "cookie": "0.5.0",
196 | "cookie-signature": "1.0.6",
197 | "debug": "2.6.9",
198 | "depd": "2.0.0",
199 | "encodeurl": "~1.0.2",
200 | "escape-html": "~1.0.3",
201 | "etag": "~1.8.1",
202 | "finalhandler": "1.2.0",
203 | "fresh": "0.5.2",
204 | "http-errors": "2.0.0",
205 | "merge-descriptors": "1.0.1",
206 | "methods": "~1.1.2",
207 | "on-finished": "2.4.1",
208 | "parseurl": "~1.3.3",
209 | "path-to-regexp": "0.1.7",
210 | "proxy-addr": "~2.0.7",
211 | "qs": "6.11.0",
212 | "range-parser": "~1.2.1",
213 | "safe-buffer": "5.2.1",
214 | "send": "0.18.0",
215 | "serve-static": "1.15.0",
216 | "setprototypeof": "1.2.0",
217 | "statuses": "2.0.1",
218 | "type-is": "~1.6.18",
219 | "utils-merge": "1.0.1",
220 | "vary": "~1.1.2"
221 | },
222 | "engines": {
223 | "node": ">= 0.10.0"
224 | }
225 | },
226 | "node_modules/finalhandler": {
227 | "version": "1.2.0",
228 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
229 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
230 | "dependencies": {
231 | "debug": "2.6.9",
232 | "encodeurl": "~1.0.2",
233 | "escape-html": "~1.0.3",
234 | "on-finished": "2.4.1",
235 | "parseurl": "~1.3.3",
236 | "statuses": "2.0.1",
237 | "unpipe": "~1.0.0"
238 | },
239 | "engines": {
240 | "node": ">= 0.8"
241 | }
242 | },
243 | "node_modules/forwarded": {
244 | "version": "0.2.0",
245 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
246 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
247 | "engines": {
248 | "node": ">= 0.6"
249 | }
250 | },
251 | "node_modules/fresh": {
252 | "version": "0.5.2",
253 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
254 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
255 | "engines": {
256 | "node": ">= 0.6"
257 | }
258 | },
259 | "node_modules/function-bind": {
260 | "version": "1.1.2",
261 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
262 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
263 | "funding": {
264 | "url": "https://github.com/sponsors/ljharb"
265 | }
266 | },
267 | "node_modules/get-intrinsic": {
268 | "version": "1.2.4",
269 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
270 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
271 | "dependencies": {
272 | "es-errors": "^1.3.0",
273 | "function-bind": "^1.1.2",
274 | "has-proto": "^1.0.1",
275 | "has-symbols": "^1.0.3",
276 | "hasown": "^2.0.0"
277 | },
278 | "engines": {
279 | "node": ">= 0.4"
280 | },
281 | "funding": {
282 | "url": "https://github.com/sponsors/ljharb"
283 | }
284 | },
285 | "node_modules/gopd": {
286 | "version": "1.0.1",
287 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
288 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
289 | "dependencies": {
290 | "get-intrinsic": "^1.1.3"
291 | },
292 | "funding": {
293 | "url": "https://github.com/sponsors/ljharb"
294 | }
295 | },
296 | "node_modules/has-property-descriptors": {
297 | "version": "1.0.1",
298 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
299 | "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
300 | "dependencies": {
301 | "get-intrinsic": "^1.2.2"
302 | },
303 | "funding": {
304 | "url": "https://github.com/sponsors/ljharb"
305 | }
306 | },
307 | "node_modules/has-proto": {
308 | "version": "1.0.1",
309 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
310 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
311 | "engines": {
312 | "node": ">= 0.4"
313 | },
314 | "funding": {
315 | "url": "https://github.com/sponsors/ljharb"
316 | }
317 | },
318 | "node_modules/has-symbols": {
319 | "version": "1.0.3",
320 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
321 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
322 | "engines": {
323 | "node": ">= 0.4"
324 | },
325 | "funding": {
326 | "url": "https://github.com/sponsors/ljharb"
327 | }
328 | },
329 | "node_modules/hasown": {
330 | "version": "2.0.1",
331 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
332 | "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
333 | "dependencies": {
334 | "function-bind": "^1.1.2"
335 | },
336 | "engines": {
337 | "node": ">= 0.4"
338 | }
339 | },
340 | "node_modules/http-errors": {
341 | "version": "2.0.0",
342 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
343 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
344 | "dependencies": {
345 | "depd": "2.0.0",
346 | "inherits": "2.0.4",
347 | "setprototypeof": "1.2.0",
348 | "statuses": "2.0.1",
349 | "toidentifier": "1.0.1"
350 | },
351 | "engines": {
352 | "node": ">= 0.8"
353 | }
354 | },
355 | "node_modules/iconv-lite": {
356 | "version": "0.4.24",
357 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
358 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
359 | "dependencies": {
360 | "safer-buffer": ">= 2.1.2 < 3"
361 | },
362 | "engines": {
363 | "node": ">=0.10.0"
364 | }
365 | },
366 | "node_modules/inherits": {
367 | "version": "2.0.4",
368 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
369 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
370 | },
371 | "node_modules/ipaddr.js": {
372 | "version": "1.9.1",
373 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
374 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
375 | "engines": {
376 | "node": ">= 0.10"
377 | }
378 | },
379 | "node_modules/media-typer": {
380 | "version": "0.3.0",
381 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
382 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
383 | "engines": {
384 | "node": ">= 0.6"
385 | }
386 | },
387 | "node_modules/merge-descriptors": {
388 | "version": "1.0.1",
389 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
390 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
391 | },
392 | "node_modules/methods": {
393 | "version": "1.1.2",
394 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
395 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
396 | "engines": {
397 | "node": ">= 0.6"
398 | }
399 | },
400 | "node_modules/mime": {
401 | "version": "1.6.0",
402 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
403 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
404 | "bin": {
405 | "mime": "cli.js"
406 | },
407 | "engines": {
408 | "node": ">=4"
409 | }
410 | },
411 | "node_modules/mime-db": {
412 | "version": "1.52.0",
413 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
414 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
415 | "engines": {
416 | "node": ">= 0.6"
417 | }
418 | },
419 | "node_modules/mime-types": {
420 | "version": "2.1.35",
421 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
422 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
423 | "dependencies": {
424 | "mime-db": "1.52.0"
425 | },
426 | "engines": {
427 | "node": ">= 0.6"
428 | }
429 | },
430 | "node_modules/ms": {
431 | "version": "2.0.0",
432 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
433 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
434 | },
435 | "node_modules/negotiator": {
436 | "version": "0.6.3",
437 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
438 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
439 | "engines": {
440 | "node": ">= 0.6"
441 | }
442 | },
443 | "node_modules/object-inspect": {
444 | "version": "1.13.1",
445 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
446 | "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
447 | "funding": {
448 | "url": "https://github.com/sponsors/ljharb"
449 | }
450 | },
451 | "node_modules/on-finished": {
452 | "version": "2.4.1",
453 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
454 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
455 | "dependencies": {
456 | "ee-first": "1.1.1"
457 | },
458 | "engines": {
459 | "node": ">= 0.8"
460 | }
461 | },
462 | "node_modules/parseurl": {
463 | "version": "1.3.3",
464 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
465 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
466 | "engines": {
467 | "node": ">= 0.8"
468 | }
469 | },
470 | "node_modules/path-to-regexp": {
471 | "version": "0.1.7",
472 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
473 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
474 | },
475 | "node_modules/proxy-addr": {
476 | "version": "2.0.7",
477 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
478 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
479 | "dependencies": {
480 | "forwarded": "0.2.0",
481 | "ipaddr.js": "1.9.1"
482 | },
483 | "engines": {
484 | "node": ">= 0.10"
485 | }
486 | },
487 | "node_modules/qs": {
488 | "version": "6.11.0",
489 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
490 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
491 | "dependencies": {
492 | "side-channel": "^1.0.4"
493 | },
494 | "engines": {
495 | "node": ">=0.6"
496 | },
497 | "funding": {
498 | "url": "https://github.com/sponsors/ljharb"
499 | }
500 | },
501 | "node_modules/range-parser": {
502 | "version": "1.2.1",
503 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
504 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
505 | "engines": {
506 | "node": ">= 0.6"
507 | }
508 | },
509 | "node_modules/raw-body": {
510 | "version": "2.5.1",
511 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
512 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
513 | "dependencies": {
514 | "bytes": "3.1.2",
515 | "http-errors": "2.0.0",
516 | "iconv-lite": "0.4.24",
517 | "unpipe": "1.0.0"
518 | },
519 | "engines": {
520 | "node": ">= 0.8"
521 | }
522 | },
523 | "node_modules/safe-buffer": {
524 | "version": "5.2.1",
525 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
526 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
527 | "funding": [
528 | {
529 | "type": "github",
530 | "url": "https://github.com/sponsors/feross"
531 | },
532 | {
533 | "type": "patreon",
534 | "url": "https://www.patreon.com/feross"
535 | },
536 | {
537 | "type": "consulting",
538 | "url": "https://feross.org/support"
539 | }
540 | ]
541 | },
542 | "node_modules/safer-buffer": {
543 | "version": "2.1.2",
544 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
545 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
546 | },
547 | "node_modules/send": {
548 | "version": "0.18.0",
549 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
550 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
551 | "dependencies": {
552 | "debug": "2.6.9",
553 | "depd": "2.0.0",
554 | "destroy": "1.2.0",
555 | "encodeurl": "~1.0.2",
556 | "escape-html": "~1.0.3",
557 | "etag": "~1.8.1",
558 | "fresh": "0.5.2",
559 | "http-errors": "2.0.0",
560 | "mime": "1.6.0",
561 | "ms": "2.1.3",
562 | "on-finished": "2.4.1",
563 | "range-parser": "~1.2.1",
564 | "statuses": "2.0.1"
565 | },
566 | "engines": {
567 | "node": ">= 0.8.0"
568 | }
569 | },
570 | "node_modules/send/node_modules/ms": {
571 | "version": "2.1.3",
572 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
573 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
574 | },
575 | "node_modules/serve-static": {
576 | "version": "1.15.0",
577 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
578 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
579 | "dependencies": {
580 | "encodeurl": "~1.0.2",
581 | "escape-html": "~1.0.3",
582 | "parseurl": "~1.3.3",
583 | "send": "0.18.0"
584 | },
585 | "engines": {
586 | "node": ">= 0.8.0"
587 | }
588 | },
589 | "node_modules/set-function-length": {
590 | "version": "1.2.1",
591 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
592 | "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
593 | "dependencies": {
594 | "define-data-property": "^1.1.2",
595 | "es-errors": "^1.3.0",
596 | "function-bind": "^1.1.2",
597 | "get-intrinsic": "^1.2.3",
598 | "gopd": "^1.0.1",
599 | "has-property-descriptors": "^1.0.1"
600 | },
601 | "engines": {
602 | "node": ">= 0.4"
603 | }
604 | },
605 | "node_modules/setprototypeof": {
606 | "version": "1.2.0",
607 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
608 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
609 | },
610 | "node_modules/side-channel": {
611 | "version": "1.0.5",
612 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
613 | "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
614 | "dependencies": {
615 | "call-bind": "^1.0.6",
616 | "es-errors": "^1.3.0",
617 | "get-intrinsic": "^1.2.4",
618 | "object-inspect": "^1.13.1"
619 | },
620 | "engines": {
621 | "node": ">= 0.4"
622 | },
623 | "funding": {
624 | "url": "https://github.com/sponsors/ljharb"
625 | }
626 | },
627 | "node_modules/statuses": {
628 | "version": "2.0.1",
629 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
630 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
631 | "engines": {
632 | "node": ">= 0.8"
633 | }
634 | },
635 | "node_modules/toidentifier": {
636 | "version": "1.0.1",
637 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
638 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
639 | "engines": {
640 | "node": ">=0.6"
641 | }
642 | },
643 | "node_modules/type-is": {
644 | "version": "1.6.18",
645 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
646 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
647 | "dependencies": {
648 | "media-typer": "0.3.0",
649 | "mime-types": "~2.1.24"
650 | },
651 | "engines": {
652 | "node": ">= 0.6"
653 | }
654 | },
655 | "node_modules/unpipe": {
656 | "version": "1.0.0",
657 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
658 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
659 | "engines": {
660 | "node": ">= 0.8"
661 | }
662 | },
663 | "node_modules/utils-merge": {
664 | "version": "1.0.1",
665 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
666 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
667 | "engines": {
668 | "node": ">= 0.4.0"
669 | }
670 | },
671 | "node_modules/vary": {
672 | "version": "1.1.2",
673 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
674 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
675 | "engines": {
676 | "node": ">= 0.8"
677 | }
678 | }
679 | }
680 | }
681 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "llama-cpp-wasm",
3 | "version": "0.3.0",
4 | "description": "WebAssembly (Wasm) Build and Bindings for llama.cpp",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/tangledgroup/llama-cpp-wasm.git"
11 | },
12 | "keywords": [
13 | "llama.cpp",
14 | "wasm",
15 | "WebAssembly",
16 | "js",
17 | "javascript",
18 | "llm",
19 | "vlm",
20 | "ai",
21 | "ml",
22 | "egde"
23 | ],
24 | "author": "Tangled Group, Inc",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/tangledgroup/llama-cpp-wasm/issues"
28 | },
29 | "homepage": "https://github.com/tangledgroup/llama-cpp-wasm#readme",
30 | "dependencies": {
31 | "express": "^4.18.2"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/llama/actions.js:
--------------------------------------------------------------------------------
1 | export const action = {
2 | LOAD: 0,
3 | INITIALIZED: 1,
4 | RUN_MAIN: 2,
5 | WRITE_RESULT: 3,
6 | RUN_COMPLETED: 4,
7 | ERROR: 5
8 | };
--------------------------------------------------------------------------------
/src/llama/llama.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 |
3 | class LlamaCpp {
4 | // callback have to be defined before load_worker
5 | constructor(url, init_callback, write_result_callback, on_complete_callback) {
6 | this.url = url;
7 | this.init_callback = init_callback;
8 | this.write_result_callback = write_result_callback;
9 | this.on_complete_callback = on_complete_callback;
10 | this.loadWorker();
11 | }
12 |
13 | loadWorker() {
14 | this.worker = new Worker(
15 | new URL("./main-worker.js", import.meta.url),
16 | {type: "module"}
17 | );
18 |
19 | this.worker.onmessage = (event) => {
20 | switch (event.data.event) {
21 | case action.INITIALIZED:
22 | // Load Model
23 | if (this.init_callback) {
24 | this.init_callback();
25 | }
26 |
27 | break;
28 | case action.WRITE_RESULT:
29 | // Capture result
30 | if (this.write_result_callback) {
31 | this.write_result_callback(event.data.text);
32 | }
33 |
34 | break;
35 | case action.RUN_COMPLETED:
36 | // Execution Completed
37 | if (this.on_complete_callback) {
38 | this.on_complete_callback();
39 | }
40 |
41 | break;
42 | }
43 | };
44 |
45 | this.worker.postMessage({
46 | event: action.LOAD,
47 | url: this.url,
48 | });
49 | }
50 |
51 | run({
52 | prompt,
53 | chatml=false,
54 | n_predict=-2,
55 | ctx_size=2048,
56 | batch_size=512,
57 | temp=0.8,
58 | n_gpu_layers=0,
59 | top_k=40,
60 | top_p=0.9,
61 | no_display_prompt=true,
62 | }={}) {
63 | this.worker.postMessage({
64 | event: action.RUN_MAIN,
65 | prompt,
66 | chatml,
67 | n_predict,
68 | ctx_size,
69 | batch_size,
70 | temp,
71 | n_gpu_layers,
72 | top_k,
73 | top_p,
74 | no_display_prompt,
75 | });
76 | }
77 | }
78 |
79 | export { LlamaCpp };
--------------------------------------------------------------------------------
/src/llama/main-worker.js:
--------------------------------------------------------------------------------
1 | import { action } from "./actions.js";
2 | import { loadBinaryResource } from "./utility.js";
3 | import Module from "./main.js";
4 |
5 | // WASM Module
6 | let module;
7 |
8 | // hard-coded filepath for loaded model in vfs
9 | const model_path = "/models/model.bin";
10 |
11 | // Function to send model line result
12 | const print = (text) => {
13 | postMessage({
14 | event: action.WRITE_RESULT,
15 | text: text,
16 | });
17 | };
18 |
19 | // Function to initialize worker
20 | // and download model file
21 | const decoder = new TextDecoder('utf-8');
22 | const punctuationBytes = [33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126];
23 | const whitespaceBytes = [32, 9, 10, 13, 11, 12];
24 | const splitBytes = [...punctuationBytes, ...whitespaceBytes];
25 | const stdoutBuffer = [];
26 |
27 | const stdin = () => {};
28 |
29 | const stdout = (c) => {
30 | stdoutBuffer.push(c);
31 |
32 | if (splitBytes.indexOf(c) == -1) {
33 | return;
34 | }
35 |
36 | const text = decoder.decode(new Uint8Array(stdoutBuffer));
37 | stdoutBuffer.splice(0, stdoutBuffer.length);
38 | print(text);
39 | };
40 |
41 | const stderr = () => {};
42 |
43 | const initWorker = async (modelPath) => {
44 | const emscrModule = {
45 | noInitialRun: true,
46 | preInit: [() => {
47 | emscrModule.TTY.register(emscrModule.FS.makedev(5, 0), {
48 | get_char: tty => stdin(tty),
49 | put_char: (tty, val) => { tty.output.push(val); stdout(val); },
50 | flush: tty => tty.output = [],
51 | fsync: tty => console.log("fsynced stdout (EmscriptenRunnable does nothing in this case)")
52 | });
53 |
54 | emscrModule.TTY.register(emscrModule.FS.makedev(6, 0), {
55 | get_char: tty => stdin(tty),
56 | put_char: (tty, val) => { tty.output.push(val); stderr(val); },
57 | flush: tty => tty.output = [],
58 | fsync: tty => console.log("fsynced stderr (EmscriptenRunnable does nothing in this case)")
59 | });
60 | }],
61 | };
62 |
63 | module = await Module(emscrModule);
64 |
65 | const initCallback = (bytes) => {
66 | // create vfs folder for storing model bins
67 | module['FS_createPath']("/", "models", true, true);
68 |
69 | // load model
70 | module['FS_createDataFile']('/models', 'model.bin', bytes, true, true, true);
71 |
72 | // update callback action to worker main thread
73 | postMessage({
74 | event: action.INITIALIZED
75 | });
76 | }
77 |
78 | loadBinaryResource(modelPath, initCallback);
79 | }
80 |
81 | const run_main = (
82 | prompt,
83 | chatml,
84 | n_predict,
85 | ctx_size,
86 | batch_size,
87 | temp,
88 | n_gpu_layers,
89 | top_k,
90 | top_p,
91 | no_display_prompt
92 | ) => {
93 | const args = [
94 | "--model", model_path,
95 | "--n-predict", n_predict.toString(),
96 | "--ctx-size", ctx_size.toString(),
97 | "--temp", temp.toString(),
98 | "--top_k", top_k.toString(),
99 | "--top_p", top_p.toString(),
100 | // "--no-mmap",
101 | "--simple-io",
102 | "--log-disable",
103 | "--prompt", prompt.toString(),
104 | ];
105 |
106 | if (!!globalThis.SharedArrayBuffer) {
107 | args.push("--threads");
108 | args.push((navigator.hardwareConcurrency).toString());
109 | }
110 |
111 | if (chatml) {
112 | args.push("--chatml");
113 | }
114 |
115 | if (no_display_prompt) {
116 | args.push("--no-display-prompt");
117 | }
118 |
119 | module['callMain'](args);
120 |
121 | postMessage({
122 | event: action.RUN_COMPLETED
123 | });
124 | }
125 |
126 | // Worker Events
127 | self.addEventListener('message', (e) => {
128 | switch (e.data.event) {
129 | case action.LOAD:
130 | // load event
131 | initWorker(e.data.url);
132 | break;
133 | case action.RUN_MAIN:
134 | // run main
135 | run_main(
136 | e.data.prompt,
137 | e.data.chatml,
138 | e.data.n_predict,
139 | e.data.ctx_size,
140 | e.data.batch_size,
141 | e.data.temp,
142 | e.data.n_gpu_layers,
143 | e.data.top_k,
144 | e.data.top_p,
145 | e.data.no_display_prompt,
146 | );
147 |
148 | break;
149 | }
150 | }, false);
151 |
--------------------------------------------------------------------------------
/src/llama/utility.js:
--------------------------------------------------------------------------------
1 | const cacheName = "llama-cpp-wasm-cache";
2 |
3 | export async function loadBinaryResource(url, callback) {
4 | let cache = null, window = self;
5 |
6 | // Try to find if the model data is cached in Web Worker memory.
7 | if (typeof window === "undefined") {
8 | console.debug("`window` is not defined");
9 | } else if (window && window.caches) {
10 | cache = await window.caches.open(cacheName);
11 | const cachedResponse = await cache.match(url);
12 |
13 | if (cachedResponse) {
14 | const data = await cachedResponse.arrayBuffer();
15 | const byteArray = new Uint8Array(data);
16 | callback(byteArray);
17 | return;
18 | }
19 | }
20 |
21 |
22 | // Download model and store in cache
23 | const req = new XMLHttpRequest();
24 | req.open("GET", url, true);
25 | req.responseType = "arraybuffer";
26 |
27 | req.onload = async (_) => {
28 | const arrayBuffer = req.response; // Note: not req.responseText
29 |
30 | if (arrayBuffer) {
31 | const byteArray = new Uint8Array(arrayBuffer);
32 |
33 | if (cache) {
34 | await cache.put(url, new Response(arrayBuffer))
35 | };
36 |
37 | callback(byteArray);
38 | }
39 | };
40 |
41 | req.send(null);
42 | }
43 |
--------------------------------------------------------------------------------