From 3d19d8357a4c30b606ed6c178a70caab36de4182 Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Wed, 27 Mar 2024 16:39:40 +0100 Subject: [PATCH] Add an image classification Rust example (#796) It accepts an image from the user and runs image classification inference. --- rust/image-classification/.gitignore | 10 + rust/image-classification/Cargo.lock | 1655 ++++++ rust/image-classification/Cargo.toml | 3 + rust/image-classification/README.md | 50 + rust/image-classification/dfx.json | 36 + rust/image-classification/download_model.sh | 11 + rust/image-classification/package-lock.json | 4540 +++++++++++++++++ rust/image-classification/package.json | 48 + rust/image-classification/rust-toolchain.toml | 4 + .../src/backend/Cargo.toml | 20 + .../src/backend/assets/logo_transparent.png | Bin 0 -> 58988 bytes .../src/backend/backend.did | 17 + .../src/backend/src/lib.rs | 42 + .../src/backend/src/onnx.rs | 1077 ++++ .../src/declarations/backend/backend.did | 17 + .../src/declarations/backend/backend.did.d.ts | 13 + .../src/declarations/backend/backend.did.js | 15 + .../src/declarations/backend/index.d.ts | 50 + .../src/declarations/backend/index.js | 42 + .../src/declarations/frontend/frontend.did | 262 + .../declarations/frontend/frontend.did.d.ts | 240 + .../src/declarations/frontend/frontend.did.js | 286 ++ .../src/declarations/frontend/index.d.ts | 50 + .../src/declarations/frontend/index.js | 42 + .../src/frontend/assets/.ic-assets.json5 | 56 + .../src/frontend/assets/default.png | Bin 0 -> 62786 bytes .../src/frontend/assets/favicon.ico | Bin 0 -> 15406 bytes .../src/frontend/assets/loader.svg | 1 + .../src/frontend/assets/logo_transparent.png | Bin 0 -> 58988 bytes .../src/frontend/assets/main.css | 162 + .../src/frontend/src/.ic-assets.json5 | 56 + .../src/frontend/src/index.html | 30 + .../src/frontend/src/index.js | 105 + rust/image-classification/webpack.config.js | 96 + 34 files changed, 9036 insertions(+) create mode 100644 rust/image-classification/.gitignore create mode 100644 rust/image-classification/Cargo.lock create mode 100644 rust/image-classification/Cargo.toml create mode 100644 rust/image-classification/README.md create mode 100644 rust/image-classification/dfx.json create mode 100755 rust/image-classification/download_model.sh create mode 100644 rust/image-classification/package-lock.json create mode 100644 rust/image-classification/package.json create mode 100644 rust/image-classification/rust-toolchain.toml create mode 100644 rust/image-classification/src/backend/Cargo.toml create mode 100644 rust/image-classification/src/backend/assets/logo_transparent.png create mode 100644 rust/image-classification/src/backend/backend.did create mode 100644 rust/image-classification/src/backend/src/lib.rs create mode 100644 rust/image-classification/src/backend/src/onnx.rs create mode 100644 rust/image-classification/src/declarations/backend/backend.did create mode 100644 rust/image-classification/src/declarations/backend/backend.did.d.ts create mode 100644 rust/image-classification/src/declarations/backend/backend.did.js create mode 100644 rust/image-classification/src/declarations/backend/index.d.ts create mode 100644 rust/image-classification/src/declarations/backend/index.js create mode 100644 rust/image-classification/src/declarations/frontend/frontend.did create mode 100644 rust/image-classification/src/declarations/frontend/frontend.did.d.ts create mode 100644 rust/image-classification/src/declarations/frontend/frontend.did.js create mode 100644 rust/image-classification/src/declarations/frontend/index.d.ts create mode 100644 rust/image-classification/src/declarations/frontend/index.js create mode 100644 rust/image-classification/src/frontend/assets/.ic-assets.json5 create mode 100644 rust/image-classification/src/frontend/assets/default.png create mode 100644 rust/image-classification/src/frontend/assets/favicon.ico create mode 100644 rust/image-classification/src/frontend/assets/loader.svg create mode 100644 rust/image-classification/src/frontend/assets/logo_transparent.png create mode 100644 rust/image-classification/src/frontend/assets/main.css create mode 100644 rust/image-classification/src/frontend/src/.ic-assets.json5 create mode 100644 rust/image-classification/src/frontend/src/index.html create mode 100644 rust/image-classification/src/frontend/src/index.js create mode 100644 rust/image-classification/webpack.config.js diff --git a/rust/image-classification/.gitignore b/rust/image-classification/.gitignore new file mode 100644 index 000000000..39b6eb4d0 --- /dev/null +++ b/rust/image-classification/.gitignore @@ -0,0 +1,10 @@ +.dfx/ +build/ +node_modules/ +dist/ +.DS_Store +_MACOSX +.vscode/ +target/ +*.old.did +.idea diff --git a/rust/image-classification/Cargo.lock b/rust/image-classification/Cargo.lock new file mode 100644 index 000000000..211235fac --- /dev/null +++ b/rust/image-classification/Cargo.lock @@ -0,0 +1,1655 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backend" +version = "1.1.0" +dependencies = [ + "anyhow", + "bytes", + "candid", + "colorgrad", + "ic-cdk", + "ic-wasi-polyfill", + "image", + "prost", + "prost-types", + "serde", + "tract-onnx", +] + +[[package]] +name = "binread" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" +dependencies = [ + "binread_derive", + "lazy_static", + "rustversion", +] + +[[package]] +name = "binread_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "candid" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088c2e3d22a0fb1ada78b968946b0f7b96027ac8669973fe7c0815a98e8d13ef" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive", + "hex", + "ic_principal", + "leb128", + "num-bigint", + "num-traits", + "paste", + "pretty", + "serde", + "serde_bytes", + "stacker", + "thiserror", +] + +[[package]] +name = "candid_derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorgrad" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5f405d474b9d05e0a093d3120e77e9bf26461b57a84b40aa2a221ac5617fb6" +dependencies = [ + "csscolorparser", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "phf", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive-new" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "function_name" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1ab577a896d09940b5fe12ec5ae71f9d8211fff62c919c03a3750a9901e98a7" +dependencies = [ + "function_name-proc-macro", +] + +[[package]] +name = "function_name-proc-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673464e1e314dd67a0fd9544abc99e8eb28d0c7e3b69b033bcff9b2d00b87333" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "ic-cdk" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3d204af0b11c45715169c997858edb58fa8407d08f4fae78a6b415dd39a362" +dependencies = [ + "candid", + "ic-cdk-macros", + "ic0", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a618e4020cea88e933d8d2f8c7f86d570ec06213506a80d4f2c520a9bba512" +dependencies = [ + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream", + "syn 1.0.109", +] + +[[package]] +name = "ic-stable-structures" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a314297eb9edb4bbcc2e04d2e634e38d5900b68eadae661e927946d1aba3f9f7" +dependencies = [ + "ic_principal", +] + +[[package]] +name = "ic-wasi-polyfill" +version = "0.3.17" +source = "git+https://github.com/wasm-forge/ic-wasi-polyfill#870e2cd0b533c03a45dbd3a516176a1fe261cea6" +dependencies = [ + "function_name", + "ic-cdk", + "ic-stable-structures", + "rand", + "stable-fs", +] + +[[package]] +name = "ic0" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a54b5297861c651551676e8c43df805dad175cc33bc97dbd992edbbb85dcbcdf" + +[[package]] +name = "ic_principal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1762deb6f7c8d8c2bdee4b6c5a47b60195b74e9b5280faa5ba29692f8e17429c" +dependencies = [ + "crc32fast", + "data-encoding", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", + "png", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "serde", + "static_assertions", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "liquid" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f68ae1011499ae2ef879f631891f21c78e309755f4a5e483c4a8f12e10b609" +dependencies = [ + "doc-comment", + "liquid-core", + "liquid-derive", + "liquid-lib", + "serde", +] + +[[package]] +name = "liquid-core" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e0724dfcaad5cfb7965ea0f178ca0870b8d7315178f4a7179f5696f7f04d5f" +dependencies = [ + "anymap2", + "itertools 0.10.5", + "kstring", + "liquid-derive", + "num-traits", + "pest", + "pest_derive", + "regex", + "serde", + "time", +] + +[[package]] +name = "liquid-derive" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2fb41a9bb4257a3803154bdf7e2df7d45197d1941c9b1a90ad815231630721" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "liquid-lib" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a17e273a6fb1fb6268f7a5867ddfd0bd4683c7e19b51084f3d567fad4348c0" +dependencies = [ + "itertools 0.10.5", + "liquid-core", + "once_cell", + "percent-encoding", + "regex", + "time", + "unicode-segmentation", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pest_meta" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + +[[package]] +name = "primal-check" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0" +dependencies = [ + "num-integer", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustfft" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", + "version_check", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scan_fmt" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" +dependencies = [ + "regex", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_tokenstream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +dependencies = [ + "proc-macro2", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "stable-fs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3bdb2e5bc9999a09abebe8e104c50db06184d4cb87249ea5d796ab7c9af669e" +dependencies = [ + "bitflags 2.4.2", + "ciborium", + "ic-cdk", + "ic-stable-structures", + "serde", + "serde_bytes", +] + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "string-interner" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f9fdfdd31a0ff38b59deb401be81b73913d76c9cc5b1aed4e1330a223420b9" +dependencies = [ + "cfg-if", + "hashbrown", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tract-core" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "anyhow", + "bit-set", + "derive-new", + "downcast-rs", + "dyn-clone", + "lazy_static", + "log", + "maplit", + "ndarray", + "num-complex", + "num-integer", + "num-traits", + "paste", + "rustfft", + "smallvec", + "tract-data", + "tract-linalg", +] + +[[package]] +name = "tract-data" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "anyhow", + "half", + "itertools 0.12.1", + "lazy_static", + "maplit", + "ndarray", + "nom", + "num-integer", + "num-traits", + "scan_fmt", + "smallvec", + "string-interner", +] + +[[package]] +name = "tract-hir" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "derive-new", + "log", + "tract-core", +] + +[[package]] +name = "tract-linalg" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "cc", + "derive-new", + "downcast-rs", + "dyn-clone", + "half", + "lazy_static", + "liquid", + "liquid-core", + "log", + "num-traits", + "paste", + "scan_fmt", + "smallvec", + "time", + "tract-data", + "unicode-normalization", + "walkdir", +] + +[[package]] +name = "tract-nnef" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "byteorder", + "flate2", + "log", + "nom", + "tar", + "tract-core", + "walkdir", +] + +[[package]] +name = "tract-onnx" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "bytes", + "derive-new", + "log", + "memmap2", + "num-integer", + "prost", + "smallvec", + "tract-hir", + "tract-nnef", + "tract-onnx-opl", +] + +[[package]] +name = "tract-onnx-opl" +version = "0.21.2-pre" +source = "git+https://github.com/sonos/tract#43b3a6689816c0797157c75e90435afa6426fd1f" +dependencies = [ + "getrandom", + "log", + "rand", + "rand_distr", + "rustfft", + "tract-nnef", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] diff --git a/rust/image-classification/Cargo.toml b/rust/image-classification/Cargo.toml new file mode 100644 index 000000000..4c16df46e --- /dev/null +++ b/rust/image-classification/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["src/backend"] +resolver = "2" diff --git a/rust/image-classification/README.md b/rust/image-classification/README.md new file mode 100644 index 000000000..0e782b721 --- /dev/null +++ b/rust/image-classification/README.md @@ -0,0 +1,50 @@ +# ICP Image Classification + +This is an ICP smart contract that accepts an image from the user and runs image classification inference. +The smart contract consists of two canisters: + +- the backend canister embeds the [the Tract ONNX inference engine](https://github.com/sonos/tract) with [the MobileNet v2-7 model](https://github.com/onnx/models/tree/main/validated/vision/classification/mobilenet). It provides a `classify()` endpoint for the frontend code to call. +- the frontend canister contains the Web assets such as HTML, JS, CSS that are served to the browser. + +Note that currently Wasm execution is not optimized for this workload. +A single call executes about 24B instructions (~10s). + +This is expected to improve in the future with: + +- faster deterministic floating-point operations. +- Wasm SIMD (Single-Instruction Multiple Data). + +The ICP mainnet subnets and `dfx` running a replica version older than [463296](https://dashboard.internetcomputer.org/release/463296c0bc82ad5999b70245e5f125c14ba7d090) may fail with an instruction-limit-exceeded error. + +# Dependencies + +Install `dfx`, Rust, etc: https://internetcomputer.org/docs/current/developer-docs/getting-started/hello-world + +Install WASI SDK 21: + +- Install `wasi-skd-21.0` from https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-21 +- Export `CC_wasm32_wasi` in your shell such that it points to WASI clang and sysroot. Example: + +``` +export CC_wasm32_wasi="/path/to/wasi-sdk-21.0/bin/clang --sysroot=/path/to/wasi-sdk-21.0/share/wasi-sysroot" +``` + +Install `wasi2ic`: +- Follow the steps in https://github.com/wasm-forge/wasi2ic +- Make sure that `wasi2ic` binary is in your `$PATH`. + +Download MobileNet v2-7 to `src/backend/assets/mobilenetv2-7.onnx`: + +``` +./downdload_model.sh +``` + +# Build + +``` +dfx start --background +dfx deploy +``` + +If the deployment is successfull, the it will show the `frontend` URL. +Open that URL in browser to interact with the smart contract. diff --git a/rust/image-classification/dfx.json b/rust/image-classification/dfx.json new file mode 100644 index 000000000..b94cbc412 --- /dev/null +++ b/rust/image-classification/dfx.json @@ -0,0 +1,36 @@ +{ + "canisters": { + "backend": { + "candid": "src/backend/backend.did", + "package": "backend", + "type": "custom", + "wasm": "target/wasm32-wasi/release/backend-ic.wasm", + "build": [ + "cargo build --release --target=wasm32-wasi", + "wasi2ic ./target/wasm32-wasi/release/backend.wasm ./target/wasm32-wasi/release/backend-ic.wasm" + ] + + }, + "frontend": { + "dependencies": [ + "backend" + ], + "frontend": { + "entrypoint": "src/frontend/src/index.html" + }, + "source": [ + "src/frontend/assets", + "dist/frontend/" + ], + "type": "assets" + } + }, + "defaults": { + "build": { + "args": "", + "packtool": "" + } + }, + "output_env_file": ".env", + "version": 1 +} diff --git a/rust/image-classification/download_model.sh b/rust/image-classification/download_model.sh new file mode 100755 index 000000000..d72cb0f12 --- /dev/null +++ b/rust/image-classification/download_model.sh @@ -0,0 +1,11 @@ +#!/bin/bash +URL="https://github.com/onnx/models/raw/main/validated/vision/classification/mobilenet/model/mobilenetv2-7.onnx?download=:" +TGT="src/backend/assets/mobilenetv2-7.onnx" +if which wget >/dev/null ; then + wget $URL -O $TGT +elif which curl >/dev/null ; then + curl -vL $URL -o $TGT +else + echo "Couldn't find wget or curl." + echo "Please download manually from \"$URL\" and save the file in $TGT." +fi diff --git a/rust/image-classification/package-lock.json b/rust/image-classification/package-lock.json new file mode 100644 index 000000000..a3b916e6a --- /dev/null +++ b/rust/image-classification/package-lock.json @@ -0,0 +1,4540 @@ +{ + "name": "icp_detect", + "version": "0.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "icp_detect", + "version": "0.2.0", + "dependencies": { + "@dfinity/agent": "^0.18.1", + "@dfinity/candid": "^0.18.1", + "@dfinity/principal": "^0.18.1" + }, + "devDependencies": { + "assert": "2.0.0", + "buffer": "6.0.3", + "copy-webpack-plugin": "^11.0.0", + "dotenv": "^16.0.3", + "events": "3.3.0", + "html-webpack-plugin": "5.5.0", + "process": "0.11.10", + "stream-browserify": "3.0.0", + "terser-webpack-plugin": "^5.3.3", + "util": "0.12.4", + "webpack": "^5.73.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.8.1" + }, + "engines": { + "node": "^12 || ^14 || ^16 || ^18 || ^21" + } + }, + "node_modules/@dfinity/agent": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.18.1.tgz", + "integrity": "sha512-nMFK/y0ZkPfQYECdojmltXsBIdGvXa1Sxa4rDV2cibEq9lsjWMEIUqPsiBaNHuwuz+gzsGVq4N2b9umKQIQaRQ==", + "dependencies": { + "base64-arraybuffer": "^0.2.0", + "borc": "^2.1.1", + "js-sha256": "0.9.0", + "simple-cbor": "^0.4.1" + }, + "peerDependencies": { + "@dfinity/candid": "^0.18.1", + "@dfinity/principal": "^0.18.1" + } + }, + "node_modules/@dfinity/candid": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-0.18.1.tgz", + "integrity": "sha512-/PC3wDnrGcWhaF/veYKevcAAn5A5jK0mRkVKcz0YxK/a78Ai9wMJg0fUk7aoyZryCOz8JPVgR4nK1/zTmvEBHg==" + }, + "node_modules/@dfinity/principal": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-0.18.1.tgz", + "integrity": "sha512-xeV+5zV7VQRT2xJTbXW4IDra1urEcchuwuKFTU/ERcJWBWEk8chsZcd6DBc8SPq83xRgXW2ZTVVSOZR8NKaVoQ==", + "dependencies": { + "js-sha256": "^0.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", + "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz", + "integrity": "sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dev": true, + "dependencies": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-arraybuffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", + "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/borc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", + "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", + "dependencies": { + "bignumber.js": "^9.0.0", + "buffer": "^5.5.0", + "commander": "^2.15.0", + "ieee754": "^1.1.13", + "iso-url": "~0.4.7", + "json-text-sequence": "~0.1.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/borc/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delimit-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", + "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/iso-url": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", + "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", + "engines": { + "node": ">=10" + } + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-text-sequence": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", + "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", + "dependencies": { + "delimit-stream": "0.1.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-cbor": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", + "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==" + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/rust/image-classification/package.json b/rust/image-classification/package.json new file mode 100644 index 000000000..82bd21c99 --- /dev/null +++ b/rust/image-classification/package.json @@ -0,0 +1,48 @@ +{ + "name": "icp_detect", + "version": "0.2.0", + "description": "Internet Computer starter application", + "keywords": [ + "Internet Computer", + "Motoko", + "JavaScript", + "Canister" + ], + "scripts": { + "build": "webpack", + "prebuild": "dfx generate", + "start": "webpack serve --mode development --env development", + "deploy:local": "dfx deploy --network=local", + "deploy:ic": "dfx deploy --network=ic", + "generate": "dfx generate backend" + }, + "dependencies": { + "@dfinity/agent": "^0.18.1", + "@dfinity/candid": "^0.18.1", + "@dfinity/principal": "^0.18.1" + }, + "devDependencies": { + "assert": "2.0.0", + "buffer": "6.0.3", + "copy-webpack-plugin": "^11.0.0", + "dotenv": "^16.0.3", + "events": "3.3.0", + "html-webpack-plugin": "5.5.0", + "process": "0.11.10", + "stream-browserify": "3.0.0", + "terser-webpack-plugin": "^5.3.3", + "util": "0.12.4", + "webpack": "^5.73.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.8.1" + }, + "engines": { + "node": "^12 || ^14 || ^16 || ^18 || ^21" + }, + "browserslist": [ + "last 2 chrome version", + "last 2 firefox version", + "last 2 safari version", + "last 2 edge version" + ] +} \ No newline at end of file diff --git a/rust/image-classification/rust-toolchain.toml b/rust/image-classification/rust-toolchain.toml new file mode 100644 index 000000000..3fbeaec6f --- /dev/null +++ b/rust/image-classification/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.75" +targets = ["wasm32-unknown-unknown"] +components = ["rustfmt", "clippy"] diff --git a/rust/image-classification/src/backend/Cargo.toml b/rust/image-classification/src/backend/Cargo.toml new file mode 100644 index 000000000..3881f2264 --- /dev/null +++ b/rust/image-classification/src/backend/Cargo.toml @@ -0,0 +1,20 @@ +[package] +edition = "2021" +name = "backend" +version = "1.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +candid = "0.10" +colorgrad = "0.6" +ic-cdk = "0.12" +bytes = "1.5.0" +prost = "0.11.0" +prost-types = "0.11.0" +image = { version = "0.24", features = ["png"], default-features = false } +serde = { version = "1.0", features = ["derive"] } +tract-onnx = { git = "https://github.com/sonos/tract", version = "=0.21.2-pre" } +ic-wasi-polyfill = { git = "https://github.com/wasm-forge/ic-wasi-polyfill", version = "0.3.17" } diff --git a/rust/image-classification/src/backend/assets/logo_transparent.png b/rust/image-classification/src/backend/assets/logo_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..94b22ca99cd8d19bc61dc1df5f003f0f9d15e848 GIT binary patch literal 58988 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 z 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 literal 0 HcmV?d00001 diff --git a/rust/image-classification/src/backend/backend.did b/rust/image-classification/src/backend/backend.did new file mode 100644 index 000000000..6837d0335 --- /dev/null +++ b/rust/image-classification/src/backend/backend.did @@ -0,0 +1,17 @@ +type Classification = record { + label: text; + score: float32; +}; + +type ClassificationError = record { + message: text; +}; + +type ClassificationResult = variant { + Ok: vec Classification; + Err: ClassificationError; +} + +service : { + "classify": (image: blob) -> (ClassificationResult); +} diff --git a/rust/image-classification/src/backend/src/lib.rs b/rust/image-classification/src/backend/src/lib.rs new file mode 100644 index 000000000..632d5d82b --- /dev/null +++ b/rust/image-classification/src/backend/src/lib.rs @@ -0,0 +1,42 @@ +use candid::{CandidType, Deserialize}; + +mod onnx; + +#[derive(CandidType, Deserialize)] +struct Classification { + label: String, + score: f32, +} + +#[derive(CandidType, Deserialize)] +struct ClassificationError { + message: String, +} + +#[derive(CandidType, Deserialize)] +enum ClassificationResult { + Ok(Vec), + Err(ClassificationError), +} + +#[ic_cdk::update] +fn classify(image: Vec) -> ClassificationResult { + let result = match onnx::classify(image) { + Ok(result) => ClassificationResult::Ok(result), + Err(err) => ClassificationResult::Err(ClassificationError { + message: err.to_string(), + }), + }; + result +} + +#[ic_cdk::init] +fn init() { + ic_wasi_polyfill::init(&[0u8; 32], &[]); + onnx::setup().unwrap(); +} + +#[ic_cdk::post_upgrade] +fn post_upgrade() { + onnx::setup().unwrap(); +} diff --git a/rust/image-classification/src/backend/src/onnx.rs b/rust/image-classification/src/backend/src/onnx.rs new file mode 100644 index 000000000..8fb5c275c --- /dev/null +++ b/rust/image-classification/src/backend/src/onnx.rs @@ -0,0 +1,1077 @@ +use std::cell::RefCell; + +use prost::Message; +use tract_onnx::prelude::*; + +use crate::Classification; + +type Model = SimplePlan, Graph>>; + +thread_local! { + static MODEL: RefCell> = RefCell::new(None); +} + +/// An image classification model trained on ImageNet dataset. +/// The model itself is not included in the source code of this example. +/// If you see a compile error here, then download the model from: +/// https://github.com/onnx/models/tree/main/validated/vision/classification/mobilenet +/// See the `download_model.sh` script for details. +const IMAGENET: &'static [u8] = include_bytes!("../assets/mobilenetv2-7.onnx"); + +/// Constructs a runnable model from the serialized ONNX model in `IMAGENET`. +pub fn setup() -> TractResult<()> { + let bytes = bytes::Bytes::from_static(IMAGENET); + let proto: tract_onnx::pb::ModelProto = tract_onnx::pb::ModelProto::decode(bytes)?; + let model = tract_onnx::onnx() + .model_for_proto_model(&proto)? + .into_optimized()? + .into_runnable()?; + MODEL.with_borrow_mut(|m| { + *m = Some(model); + }); + Ok(()) +} + +/// Runs the model on the given image and returns top three labels. +pub fn classify(image: Vec) -> Result, anyhow::Error> { + MODEL.with_borrow(|model| { + let model = model.as_ref().unwrap(); + let image = image::load_from_memory(&image)?.to_rgb8(); + + // The model accepts an image of size 224x224px. + let image = + image::imageops::resize(&image, 224, 224, ::image::imageops::FilterType::Triangle); + + // Preprocess the input according to + // https://github.com/onnx/models/tree/main/validated/vision/classification/mobilenet#preprocessing. + const MEAN: [f32; 3] = [0.485, 0.456, 0.406]; + const STD: [f32; 3] = [0.229, 0.224, 0.225]; + let tensor = tract_ndarray::Array4::from_shape_fn((1, 3, 224, 224), |(_, c, y, x)| { + (image[(x as u32, y as u32)][c] as f32 / 255.0 - MEAN[c]) / STD[c] + }); + + let result = model.run(tvec!(Tensor::from(tensor).into()))?; + + let mut scores: Vec<_> = result[0] + .to_array_view::()? + .into_iter() + .zip(0..) + .collect(); + + scores.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap()); + + let labels = scores + .iter() + .take(3) + .map(|(score, i)| Classification { + label: LABELS[*i as usize].to_string(), + score: **score, + }) + .collect(); + Ok(labels) + }) +} + +/// The set of 1000 ImageNet class labels. +const LABELS: [&'static str; 1000] = [ + "tench", + "goldfish", + "great white shark", + "tiger shark", + "hammerhead", + "electric ray", + "stingray", + "cock", + "hen", + "ostrich", + "brambling", + "goldfinch", + "house finch", + "junco", + "indigo bunting", + "robin", + "bulbul", + "jay", + "magpie", + "chickadee", + "water ouzel", + "kite", + "bald eagle", + "vulture", + "great grey owl", + "european fire salamander", + "common newt", + "eft", + "spotted salamander", + "axolotl", + "bullfrog", + "tree frog", + "tailed frog", + "loggerhead", + "leatherback turtle", + "mud turtle", + "terrapin", + "box turtle", + "banded gecko", + "common iguana", + "american chameleon", + "whiptail", + "agama", + "frilled lizard", + "alligator lizard", + "gila monster", + "green lizard", + "african chameleon", + "komodo dragon", + "african crocodile", + "american alligator", + "triceratops", + "thunder snake", + "ringneck snake", + "hognose snake", + "green snake", + "king snake", + "garter snake", + "water snake", + "vine snake", + "night snake", + "boa constrictor", + "rock python", + "indian cobra", + "green mamba", + "sea snake", + "horned viper", + "diamondback", + "sidewinder", + "trilobite", + "harvestman", + "scorpion", + "black and gold garden spider", + "barn spider", + "garden spider", + "black widow", + "tarantula", + "wolf spider", + "tick", + "centipede", + "black grouse", + "ptarmigan", + "ruffed grouse", + "prairie chicken", + "peacock", + "quail", + "partridge", + "african grey", + "macaw", + "sulphur-crested cockatoo", + "lorikeet", + "coucal", + "bee eater", + "hornbill", + "hummingbird", + "jacamar", + "toucan", + "drake", + "red-breasted merganser", + "goose", + "black swan", + "tusker", + "echidna", + "platypus", + "wallaby", + "koala", + "wombat", + "jellyfish", + "sea anemone", + "brain coral", + "flatworm", + "nematode", + "conch", + "snail", + "slug", + "sea slug", + "chiton", + "chambered nautilus", + "dungeness crab", + "rock crab", + "fiddler crab", + "king crab", + "american lobster", + "spiny lobster", + "crayfish", + "hermit crab", + "isopod", + "white stork", + "black stork", + "spoonbill", + "flamingo", + "little blue heron", + "american egret", + "bittern", + "crane", + "limpkin", + "european gallinule", + "american coot", + "bustard", + "ruddy turnstone", + "red-backed sandpiper", + "redshank", + "dowitcher", + "oystercatcher", + "pelican", + "king penguin", + "albatross", + "grey whale", + "killer whale", + "dugong", + "sea lion", + "chihuahua", + "japanese spaniel", + "maltese dog", + "pekinese", + "shih-tzu", + "blenheim spaniel", + "papillon", + "toy terrier", + "rhodesian ridgeback", + "afghan hound", + "basset", + "beagle", + "bloodhound", + "bluetick", + "black-and-tan coonhound", + "walker hound", + "english foxhound", + "redbone", + "borzoi", + "irish wolfhound", + "italian greyhound", + "whippet", + "ibizan hound", + "norwegian elkhound", + "otterhound", + "saluki", + "scottish deerhound", + "weimaraner", + "staffordshire bullterrier", + "american staffordshire terrier", + "bedlington terrier", + "border terrier", + "kerry blue terrier", + "irish terrier", + "norfolk terrier", + "norwich terrier", + "yorkshire terrier", + "wire-haired fox terrier", + "lakeland terrier", + "sealyham terrier", + "airedale", + "cairn", + "australian terrier", + "dandie dinmont", + "boston bull", + "miniature schnauzer", + "giant schnauzer", + "standard schnauzer", + "scotch terrier", + "tibetan terrier", + "silky terrier", + "soft-coated wheaten terrier", + "west highland white terrier", + "lhasa", + "flat-coated retriever", + "curly-coated retriever", + "golden retriever", + "labrador retriever", + "chesapeake bay retriever", + "german short-haired pointer", + "vizsla", + "english setter", + "irish setter", + "gordon setter", + "brittany spaniel", + "clumber", + "english springer", + "welsh springer spaniel", + "cocker spaniel", + "sussex spaniel", + "irish water spaniel", + "kuvasz", + "schipperke", + "groenendael", + "malinois", + "briard", + "kelpie", + "komondor", + "old english sheepdog", + "shetland sheepdog", + "collie", + "border collie", + "bouvier des flandres", + "rottweiler", + "german shepherd", + "doberman", + "miniature pinscher", + "greater swiss mountain dog", + "bernese mountain dog", + "appenzeller", + "entlebucher", + "boxer", + "bull mastiff", + "tibetan mastiff", + "french bulldog", + "great dane", + "saint bernard", + "eskimo dog", + "malamute", + "siberian husky", + "dalmatian", + "affenpinscher", + "basenji", + "pug", + "leonberg", + "newfoundland", + "great pyrenees", + "samoyed", + "pomeranian", + "chow", + "keeshond", + "brabancon griffon", + "pembroke", + "cardigan", + "toy poodle", + "miniature poodle", + "standard poodle", + "mexican hairless", + "timber wolf", + "white wolf", + "red wolf", + "coyote", + "dingo", + "dhole", + "african hunting dog", + "hyena", + "red fox", + "kit fox", + "arctic fox", + "grey fox", + "tabby", + "tiger cat", + "persian cat", + "siamese cat", + "egyptian cat", + "cougar", + "lynx", + "leopard", + "snow leopard", + "jaguar", + "lion", + "tiger", + "cheetah", + "brown bear", + "american black bear", + "ice bear", + "sloth bear", + "mongoose", + "meerkat", + "tiger beetle", + "ladybug", + "ground beetle", + "long-horned beetle", + "leaf beetle", + "dung beetle", + "rhinoceros beetle", + "weevil", + "fly", + "bee", + "ant", + "grasshopper", + "cricket", + "walking stick", + "cockroach", + "mantis", + "cicada", + "leafhopper", + "lacewing", + "dragonfly", + "damselfly", + "admiral", + "ringlet", + "monarch", + "cabbage butterfly", + "sulphur butterfly", + "lycaenid", + "starfish", + "sea urchin", + "sea cucumber", + "wood rabbit", + "hare", + "angora", + "hamster", + "porcupine", + "fox squirrel", + "marmot", + "beaver", + "guinea pig", + "sorrel", + "zebra", + "hog", + "wild boar", + "warthog", + "hippopotamus", + "ox", + "water buffalo", + "bison", + "ram", + "bighorn", + "ibex", + "hartebeest", + "impala", + "gazelle", + "arabian camel", + "llama", + "weasel", + "mink", + "polecat", + "black-footed ferret", + "otter", + "skunk", + "badger", + "armadillo", + "three-toed sloth", + "orangutan", + "gorilla", + "chimpanzee", + "gibbon", + "siamang", + "guenon", + "patas", + "baboon", + "macaque", + "langur", + "colobus", + "proboscis monkey", + "marmoset", + "capuchin", + "howler monkey", + "titi", + "spider monkey", + "squirrel monkey", + "madagascar cat", + "indri", + "indian elephant", + "african elephant", + "lesser panda", + "giant panda", + "barracouta", + "eel", + "coho", + "rock beauty", + "anemone fish", + "sturgeon", + "gar", + "lionfish", + "puffer", + "abacus", + "abaya", + "academic gown", + "accordion", + "acoustic guitar", + "aircraft carrier", + "airliner", + "airship", + "altar", + "ambulance", + "amphibian", + "analog clock", + "apiary", + "apron", + "ashcan", + "assault rifle", + "backpack", + "bakery", + "balance beam", + "balloon", + "ballpoint", + "band aid", + "banjo", + "bannister", + "barbell", + "barber chair", + "barbershop", + "barn", + "barometer", + "barrel", + "barrow", + "baseball", + "basketball", + "bassinet", + "bassoon", + "bathing cap", + "bath towel", + "bathtub", + "beach wagon", + "beacon", + "beaker", + "bearskin", + "beer bottle", + "beer glass", + "bell cote", + "bib", + "bicycle-built-for-two", + "bikini", + "binder", + "binoculars", + "birdhouse", + "boathouse", + "bobsled", + "bolo tie", + "bonnet", + "bookcase", + "bookshop", + "bottlecap", + "bow", + "bow tie", + "brass", + "brassiere", + "breakwater", + "breastplate", + "broom", + "bucket", + "buckle", + "bulletproof vest", + "bullet train", + "butcher shop", + "cab", + "caldron", + "candle", + "cannon", + "canoe", + "can opener", + "cardigan", + "car mirror", + "carousel", + "carpenter's kit", + "carton", + "car wheel", + "cash machine", + "cassette", + "cassette player", + "castle", + "catamaran", + "cd player", + "cello", + "cellular telephone", + "chain", + "chainlink fence", + "chain mail", + "chain saw", + "chest", + "chiffonier", + "chime", + "china cabinet", + "christmas stocking", + "church", + "cinema", + "cleaver", + "cliff dwelling", + "cloak", + "clog", + "cocktail shaker", + "coffee mug", + "coffeepot", + "coil", + "combination lock", + "computer keyboard", + "confectionery", + "container ship", + "convertible", + "corkscrew", + "cornet", + "cowboy boot", + "cowboy hat", + "cradle", + "crane", + "crash helmet", + "crate", + "crib", + "crock pot", + "croquet ball", + "crutch", + "cuirass", + "dam", + "desk", + "desktop computer", + "dial telephone", + "diaper", + "digital clock", + "digital watch", + "dining table", + "dishrag", + "dishwasher", + "disk brake", + "dock", + "dogsled", + "dome", + "doormat", + "drilling platform", + "drum", + "drumstick", + "dumbbell", + "dutch oven", + "electric fan", + "electric guitar", + "electric locomotive", + "entertainment center", + "envelope", + "espresso maker", + "face powder", + "feather boa", + "file", + "fireboat", + "fire engine", + "fire screen", + "flagpole", + "flute", + "folding chair", + "football helmet", + "forklift", + "fountain", + "fountain pen", + "four-poster", + "freight car", + "french horn", + "frying pan", + "fur coat", + "garbage truck", + "gasmask", + "gas pump", + "goblet", + "go-kart", + "golf ball", + "golfcart", + "gondola", + "gong", + "gown", + "grand piano", + "greenhouse", + "grille", + "grocery store", + "guillotine", + "hair slide", + "hair spray", + "half track", + "hammer", + "hamper", + "hand blower", + "hand-held computer", + "handkerchief", + "hard disc", + "harmonica", + "harp", + "harvester", + "hatchet", + "holster", + "home theater", + "honeycomb", + "hook", + "hoopskirt", + "horizontal bar", + "horse cart", + "hourglass", + "ipod", + "iron", + "jack-o'-lantern", + "jean", + "jeep", + "jersey", + "jigsaw puzzle", + "jinrikisha", + "joystick", + "kimono", + "knee pad", + "knot", + "lab coat", + "ladle", + "lampshade", + "laptop", + "lawn mower", + "lens cap", + "letter opener", + "library", + "lifeboat", + "lighter", + "limousine", + "liner", + "lipstick", + "loafer", + "lotion", + "loudspeaker", + "loupe", + "lumbermill", + "magnetic compass", + "mailbag", + "mailbox", + "maillot", + "maillot", + "manhole cover", + "maraca", + "marimba", + "mask", + "matchstick", + "maypole", + "maze", + "measuring cup", + "medicine chest", + "megalith", + "microphone", + "microwave", + "military uniform", + "milk can", + "minibus", + "miniskirt", + "minivan", + "missile", + "mitten", + "mixing bowl", + "mobile home", + "model t", + "modem", + "monastery", + "monitor", + "moped", + "mortar", + "mortarboard", + "mosque", + "mosquito net", + "motor scooter", + "mountain bike", + "mountain tent", + "mouse", + "mousetrap", + "moving van", + "muzzle", + "nail", + "neck brace", + "necklace", + "nipple", + "notebook", + "obelisk", + "oboe", + "ocarina", + "odometer", + "oil filter", + "organ", + "oscilloscope", + "overskirt", + "oxcart", + "oxygen mask", + "packet", + "paddle", + "paddlewheel", + "padlock", + "paintbrush", + "pajama", + "palace", + "panpipe", + "paper towel", + "parachute", + "parallel bars", + "park bench", + "parking meter", + "passenger car", + "patio", + "pay-phone", + "pedestal", + "pencil box", + "pencil sharpener", + "perfume", + "petri dish", + "photocopier", + "pick", + "pickelhaube", + "picket fence", + "pickup", + "pier", + "piggy bank", + "pill bottle", + "pillow", + "ping-pong ball", + "pinwheel", + "pirate", + "pitcher", + "plane", + "planetarium", + "plastic bag", + "plate rack", + "plow", + "plunger", + "polaroid camera", + "pole", + "police van", + "poncho", + "pool table", + "pop bottle", + "pot", + "potter's wheel", + "power drill", + "prayer rug", + "printer", + "prison", + "projectile", + "projector", + "puck", + "punching bag", + "purse", + "quill", + "quilt", + "racer", + "racket", + "radiator", + "radio", + "radio telescope", + "rain barrel", + "recreational vehicle", + "reel", + "reflex camera", + "refrigerator", + "remote control", + "restaurant", + "revolver", + "rifle", + "rocking chair", + "rotisserie", + "rubber eraser", + "rugby ball", + "rule", + "running shoe", + "safe", + "safety pin", + "saltshaker", + "sandal", + "sarong", + "sax", + "scabbard", + "scale", + "school bus", + "schooner", + "scoreboard", + "screen", + "screw", + "screwdriver", + "seat belt", + "sewing machine", + "shield", + "shoe shop", + "shoji", + "shopping basket", + "shopping cart", + "shovel", + "shower cap", + "shower curtain", + "ski", + "ski mask", + "sleeping bag", + "slide rule", + "sliding door", + "slot", + "snorkel", + "snowmobile", + "snowplow", + "soap dispenser", + "soccer ball", + "sock", + "solar dish", + "sombrero", + "soup bowl", + "space bar", + "space heater", + "space shuttle", + "spatula", + "speedboat", + "spider web", + "spindle", + "sports car", + "spotlight", + "stage", + "steam locomotive", + "steel arch bridge", + "steel drum", + "stethoscope", + "stole", + "stone wall", + "stopwatch", + "stove", + "strainer", + "streetcar", + "stretcher", + "studio couch", + "stupa", + "submarine", + "suit", + "sundial", + "sunglass", + "sunglasses", + "sunscreen", + "suspension bridge", + "swab", + "sweatshirt", + "swimming trunks", + "swing", + "switch", + "syringe", + "table lamp", + "tank", + "tape player", + "teapot", + "teddy", + "television", + "tennis ball", + "thatch", + "theater curtain", + "thimble", + "thresher", + "throne", + "tile roof", + "toaster", + "tobacco shop", + "toilet seat", + "torch", + "totem pole", + "tow truck", + "toyshop", + "tractor", + "trailer truck", + "tray", + "trench coat", + "tricycle", + "trimaran", + "tripod", + "triumphal arch", + "trolleybus", + "trombone", + "tub", + "turnstile", + "typewriter keyboard", + "umbrella", + "unicycle", + "upright", + "vacuum", + "vase", + "vault", + "velvet", + "vending machine", + "vestment", + "viaduct", + "violin", + "volleyball", + "waffle iron", + "wall clock", + "wallet", + "wardrobe", + "warplane", + "washbasin", + "washer", + "water bottle", + "water jug", + "water tower", + "whiskey jug", + "whistle", + "wig", + "window screen", + "window shade", + "windsor tie", + "wine bottle", + "wing", + "wok", + "wooden spoon", + "wool", + "worm fence", + "wreck", + "yawl", + "yurt", + "web site", + "comic book", + "crossword puzzle", + "street sign", + "traffic light", + "book jacket", + "menu", + "plate", + "guacamole", + "consomme", + "hot pot", + "trifle", + "ice cream", + "ice lolly", + "french loaf", + "bagel", + "pretzel", + "cheeseburger", + "hotdog", + "mashed potato", + "head cabbage", + "broccoli", + "cauliflower", + "zucchini", + "spaghetti squash", + "acorn squash", + "butternut squash", + "cucumber", + "artichoke", + "bell pepper", + "cardoon", + "mushroom", + "granny smith", + "strawberry", + "orange", + "lemon", + "fig", + "pineapple", + "banana", + "jackfruit", + "custard apple", + "pomegranate", + "hay", + "carbonara", + "chocolate sauce", + "dough", + "meat loaf", + "pizza", + "potpie", + "burrito", + "red wine", + "espresso", + "cup", + "eggnog", + "alp", + "bubble", + "cliff", + "coral reef", + "geyser", + "lakeside", + "promontory", + "sandbar", + "seashore", + "valley", + "volcano", + "ballplayer", + "groom", + "scuba diver", + "rapeseed", + "daisy", + "yellow lady's slipper", + "corn", + "acorn", + "hip", + "buckeye", + "coral fungus", + "agaric", + "gyromitra", + "stinkhorn", + "earthstar", + "hen-of-the-woods", + "bolete", + "ear", + "toilet tissue", +]; diff --git a/rust/image-classification/src/declarations/backend/backend.did b/rust/image-classification/src/declarations/backend/backend.did new file mode 100644 index 000000000..6837d0335 --- /dev/null +++ b/rust/image-classification/src/declarations/backend/backend.did @@ -0,0 +1,17 @@ +type Classification = record { + label: text; + score: float32; +}; + +type ClassificationError = record { + message: text; +}; + +type ClassificationResult = variant { + Ok: vec Classification; + Err: ClassificationError; +} + +service : { + "classify": (image: blob) -> (ClassificationResult); +} diff --git a/rust/image-classification/src/declarations/backend/backend.did.d.ts b/rust/image-classification/src/declarations/backend/backend.did.d.ts new file mode 100644 index 000000000..7680fb218 --- /dev/null +++ b/rust/image-classification/src/declarations/backend/backend.did.d.ts @@ -0,0 +1,13 @@ +import type { Principal } from '@dfinity/principal'; +import type { ActorMethod } from '@dfinity/agent'; +import type { IDL } from '@dfinity/candid'; + +export interface Classification { 'label' : string, 'score' : number } +export interface ClassificationError { 'message' : string } +export type ClassificationResult = { 'Ok' : Array } | + { 'Err' : ClassificationError }; +export interface _SERVICE { + 'classify' : ActorMethod<[Uint8Array | number[]], ClassificationResult>, +} +export declare const idlFactory: IDL.InterfaceFactory; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/rust/image-classification/src/declarations/backend/backend.did.js b/rust/image-classification/src/declarations/backend/backend.did.js new file mode 100644 index 000000000..197a8029d --- /dev/null +++ b/rust/image-classification/src/declarations/backend/backend.did.js @@ -0,0 +1,15 @@ +export const idlFactory = ({ IDL }) => { + const Classification = IDL.Record({ + 'label' : IDL.Text, + 'score' : IDL.Float32, + }); + const ClassificationError = IDL.Record({ 'message' : IDL.Text }); + const ClassificationResult = IDL.Variant({ + 'Ok' : IDL.Vec(Classification), + 'Err' : ClassificationError, + }); + return IDL.Service({ + 'classify' : IDL.Func([IDL.Vec(IDL.Nat8)], [ClassificationResult], []), + }); +}; +export const init = ({ IDL }) => { return []; }; diff --git a/rust/image-classification/src/declarations/backend/index.d.ts b/rust/image-classification/src/declarations/backend/index.d.ts new file mode 100644 index 000000000..55daa14e7 --- /dev/null +++ b/rust/image-classification/src/declarations/backend/index.d.ts @@ -0,0 +1,50 @@ +import type { + ActorSubclass, + HttpAgentOptions, + ActorConfig, + Agent, +} from "@dfinity/agent"; +import type { Principal } from "@dfinity/principal"; +import type { IDL } from "@dfinity/candid"; + +import { _SERVICE } from './backend.did'; + +export declare const idlFactory: IDL.InterfaceFactory; +export declare const canisterId: string; + +export declare interface CreateActorOptions { + /** + * @see {@link Agent} + */ + agent?: Agent; + /** + * @see {@link HttpAgentOptions} + */ + agentOptions?: HttpAgentOptions; + /** + * @see {@link ActorConfig} + */ + actorOptions?: ActorConfig; +} + +/** + * Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister. + * @constructs {@link ActorSubClass} + * @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to + * @param {CreateActorOptions} options - see {@link CreateActorOptions} + * @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions + * @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent + * @see {@link HttpAgentOptions} + * @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor + * @see {@link ActorConfig} + */ +export declare const createActor: ( + canisterId: string | Principal, + options?: CreateActorOptions +) => ActorSubclass<_SERVICE>; + +/** + * Intialized Actor using default settings, ready to talk to a canister using its candid interface + * @constructs {@link ActorSubClass} + */ +export declare const backend: ActorSubclass<_SERVICE>; diff --git a/rust/image-classification/src/declarations/backend/index.js b/rust/image-classification/src/declarations/backend/index.js new file mode 100644 index 000000000..8def37967 --- /dev/null +++ b/rust/image-classification/src/declarations/backend/index.js @@ -0,0 +1,42 @@ +import { Actor, HttpAgent } from "@dfinity/agent"; + +// Imports and re-exports candid interface +import { idlFactory } from "./backend.did.js"; +export { idlFactory } from "./backend.did.js"; + +/* CANISTER_ID is replaced by webpack based on node environment + * Note: canister environment variable will be standardized as + * process.env.CANISTER_ID_ + * beginning in dfx 0.15.0 + */ +export const canisterId = + process.env.CANISTER_ID_BACKEND; + +export const createActor = (canisterId, options = {}) => { + const agent = options.agent || new HttpAgent({ ...options.agentOptions }); + + if (options.agent && options.agentOptions) { + console.warn( + "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." + ); + } + + // Fetch root key for certificate validation during development + if (process.env.DFX_NETWORK !== "ic") { + agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); + console.error(err); + }); + } + + // Creates an actor with using the candid interface and the HttpAgent + return Actor.createActor(idlFactory, { + agent, + canisterId, + ...options.actorOptions, + }); +}; + +export const backend = canisterId ? createActor(canisterId) : undefined; diff --git a/rust/image-classification/src/declarations/frontend/frontend.did b/rust/image-classification/src/declarations/frontend/frontend.did new file mode 100644 index 000000000..51bb1a235 --- /dev/null +++ b/rust/image-classification/src/declarations/frontend/frontend.did @@ -0,0 +1,262 @@ +type BatchId = nat; +type ChunkId = nat; +type Key = text; +type Time = int; + +type CreateAssetArguments = record { + key: Key; + content_type: text; + max_age: opt nat64; + headers: opt vec HeaderField; + enable_aliasing: opt bool; + allow_raw_access: opt bool; +}; + +// Add or change content for an asset, by content encoding +type SetAssetContentArguments = record { + key: Key; + content_encoding: text; + chunk_ids: vec ChunkId; + sha256: opt blob; +}; + +// Remove content for an asset, by content encoding +type UnsetAssetContentArguments = record { + key: Key; + content_encoding: text; +}; + +// Delete an asset +type DeleteAssetArguments = record { + key: Key; +}; + +// Reset everything +type ClearArguments = record {}; + +type BatchOperationKind = variant { + CreateAsset: CreateAssetArguments; + SetAssetContent: SetAssetContentArguments; + + SetAssetProperties: SetAssetPropertiesArguments; + + UnsetAssetContent: UnsetAssetContentArguments; + DeleteAsset: DeleteAssetArguments; + + Clear: ClearArguments; +}; + +type CommitBatchArguments = record { + batch_id: BatchId; + operations: vec BatchOperationKind +}; + +type CommitProposedBatchArguments = record { + batch_id: BatchId; + evidence: blob; +}; + +type ComputeEvidenceArguments = record { + batch_id: BatchId; + max_iterations: opt nat16 +}; + +type DeleteBatchArguments = record { + batch_id: BatchId; +}; + +type HeaderField = record { text; text; }; + +type HttpRequest = record { + method: text; + url: text; + headers: vec HeaderField; + body: blob; + certificate_version: opt nat16; +}; + +type HttpResponse = record { + status_code: nat16; + headers: vec HeaderField; + body: blob; + streaming_strategy: opt StreamingStrategy; +}; + +type StreamingCallbackHttpResponse = record { + body: blob; + token: opt StreamingCallbackToken; +}; + +type StreamingCallbackToken = record { + key: Key; + content_encoding: text; + index: nat; + sha256: opt blob; +}; + +type StreamingStrategy = variant { + Callback: record { + callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; + token: StreamingCallbackToken; + }; +}; + +type SetAssetPropertiesArguments = record { + key: Key; + max_age: opt opt nat64; + headers: opt opt vec HeaderField; + allow_raw_access: opt opt bool; + is_aliased: opt opt bool; +}; + +type ConfigurationResponse = record { + max_batches: opt nat64; + max_chunks: opt nat64; + max_bytes: opt nat64; +}; + +type ConfigureArguments = record { + max_batches: opt opt nat64; + max_chunks: opt opt nat64; + max_bytes: opt opt nat64; +}; + +type Permission = variant { + Commit; + ManagePermissions; + Prepare; +}; + +type GrantPermission = record { + to_principal: principal; + permission: Permission; +}; +type RevokePermission = record { + of_principal: principal; + permission: Permission; +}; +type ListPermitted = record { permission: Permission }; + +type ValidationResult = variant { Ok : text; Err : text }; + +type AssetCanisterArgs = variant { + Init: InitArgs; + Upgrade: UpgradeArgs; +}; + +type InitArgs = record {}; + +type UpgradeArgs = record { + set_permissions: opt SetPermissions; +}; + +/// Sets the list of principals granted each permission. +type SetPermissions = record { + prepare: vec principal; + commit: vec principal; + manage_permissions: vec principal; +}; + +service: (asset_canister_args: opt AssetCanisterArgs) -> { + api_version: () -> (nat16) query; + + get: (record { + key: Key; + accept_encodings: vec text; + }) -> (record { + content: blob; // may be the entirety of the content, or just chunk index 0 + content_type: text; + content_encoding: text; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + total_length: nat; // all chunks except last have size == content.size() + }) query; + + // if get() returned chunks > 1, call this to retrieve them. + // chunks may or may not be split up at the same boundaries as presented to create_chunk(). + get_chunk: (record { + key: Key; + content_encoding: text; + index: nat; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + }) -> (record { content: blob }) query; + + list : (record {}) -> (vec record { + key: Key; + content_type: text; + encodings: vec record { + content_encoding: text; + sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments + length: nat; // Size of this encoding's blob. Calculated when uploading assets. + modified: Time; + }; + }) query; + + certified_tree : (record {}) -> (record { + certificate: blob; + tree: blob; + }) query; + + create_batch : (record {}) -> (record { batch_id: BatchId }); + + create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); + + // Perform all operations successfully, or reject + commit_batch: (CommitBatchArguments) -> (); + + // Save the batch operations for later commit + propose_commit_batch: (CommitBatchArguments) -> (); + + // Given a batch already proposed, perform all operations successfully, or reject + commit_proposed_batch: (CommitProposedBatchArguments) -> (); + + // Compute a hash over the CommitBatchArguments. Call until it returns Some(evidence). + compute_evidence: (ComputeEvidenceArguments) -> (opt blob); + + // Delete a batch that has been created, or proposed for commit, but not yet committed + delete_batch: (DeleteBatchArguments) -> (); + + create_asset: (CreateAssetArguments) -> (); + set_asset_content: (SetAssetContentArguments) -> (); + unset_asset_content: (UnsetAssetContentArguments) -> (); + + delete_asset: (DeleteAssetArguments) -> (); + + clear: (ClearArguments) -> (); + + // Single call to create an asset with content for a single content encoding that + // fits within the message ingress limit. + store: (record { + key: Key; + content_type: text; + content_encoding: text; + content: blob; + sha256: opt blob + }) -> (); + + http_request: (request: HttpRequest) -> (HttpResponse) query; + http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; + + authorize: (principal) -> (); + deauthorize: (principal) -> (); + list_authorized: () -> (vec principal); + grant_permission: (GrantPermission) -> (); + revoke_permission: (RevokePermission) -> (); + list_permitted: (ListPermitted) -> (vec principal); + take_ownership: () -> (); + + get_asset_properties : (key: Key) -> (record { + max_age: opt nat64; + headers: opt vec HeaderField; + allow_raw_access: opt bool; + is_aliased: opt bool; } ) query; + set_asset_properties: (SetAssetPropertiesArguments) -> (); + + get_configuration: () -> (ConfigurationResponse); + configure: (ConfigureArguments) -> (); + + validate_grant_permission: (GrantPermission) -> (ValidationResult); + validate_revoke_permission: (RevokePermission) -> (ValidationResult); + validate_take_ownership: () -> (ValidationResult); + validate_commit_proposed_batch: (CommitProposedBatchArguments) -> (ValidationResult); + validate_configure: (ConfigureArguments) -> (ValidationResult); +} diff --git a/rust/image-classification/src/declarations/frontend/frontend.did.d.ts b/rust/image-classification/src/declarations/frontend/frontend.did.d.ts new file mode 100644 index 000000000..ce964689f --- /dev/null +++ b/rust/image-classification/src/declarations/frontend/frontend.did.d.ts @@ -0,0 +1,240 @@ +import type { Principal } from '@dfinity/principal'; +import type { ActorMethod } from '@dfinity/agent'; +import type { IDL } from '@dfinity/candid'; + +export type AssetCanisterArgs = { 'Upgrade' : UpgradeArgs } | + { 'Init' : InitArgs }; +export type BatchId = bigint; +export type BatchOperationKind = { + 'SetAssetProperties' : SetAssetPropertiesArguments + } | + { 'CreateAsset' : CreateAssetArguments } | + { 'UnsetAssetContent' : UnsetAssetContentArguments } | + { 'DeleteAsset' : DeleteAssetArguments } | + { 'SetAssetContent' : SetAssetContentArguments } | + { 'Clear' : ClearArguments }; +export type ChunkId = bigint; +export type ClearArguments = {}; +export interface CommitBatchArguments { + 'batch_id' : BatchId, + 'operations' : Array, +} +export interface CommitProposedBatchArguments { + 'batch_id' : BatchId, + 'evidence' : Uint8Array | number[], +} +export interface ComputeEvidenceArguments { + 'batch_id' : BatchId, + 'max_iterations' : [] | [number], +} +export interface ConfigurationResponse { + 'max_batches' : [] | [bigint], + 'max_bytes' : [] | [bigint], + 'max_chunks' : [] | [bigint], +} +export interface ConfigureArguments { + 'max_batches' : [] | [[] | [bigint]], + 'max_bytes' : [] | [[] | [bigint]], + 'max_chunks' : [] | [[] | [bigint]], +} +export interface CreateAssetArguments { + 'key' : Key, + 'content_type' : string, + 'headers' : [] | [Array], + 'allow_raw_access' : [] | [boolean], + 'max_age' : [] | [bigint], + 'enable_aliasing' : [] | [boolean], +} +export interface DeleteAssetArguments { 'key' : Key } +export interface DeleteBatchArguments { 'batch_id' : BatchId } +export interface GrantPermission { + 'permission' : Permission, + 'to_principal' : Principal, +} +export type HeaderField = [string, string]; +export interface HttpRequest { + 'url' : string, + 'method' : string, + 'body' : Uint8Array | number[], + 'headers' : Array, + 'certificate_version' : [] | [number], +} +export interface HttpResponse { + 'body' : Uint8Array | number[], + 'headers' : Array, + 'streaming_strategy' : [] | [StreamingStrategy], + 'status_code' : number, +} +export type InitArgs = {}; +export type Key = string; +export interface ListPermitted { 'permission' : Permission } +export type Permission = { 'Prepare' : null } | + { 'ManagePermissions' : null } | + { 'Commit' : null }; +export interface RevokePermission { + 'permission' : Permission, + 'of_principal' : Principal, +} +export interface SetAssetContentArguments { + 'key' : Key, + 'sha256' : [] | [Uint8Array | number[]], + 'chunk_ids' : Array, + 'content_encoding' : string, +} +export interface SetAssetPropertiesArguments { + 'key' : Key, + 'headers' : [] | [[] | [Array]], + 'is_aliased' : [] | [[] | [boolean]], + 'allow_raw_access' : [] | [[] | [boolean]], + 'max_age' : [] | [[] | [bigint]], +} +export interface SetPermissions { + 'prepare' : Array, + 'commit' : Array, + 'manage_permissions' : Array, +} +export interface StreamingCallbackHttpResponse { + 'token' : [] | [StreamingCallbackToken], + 'body' : Uint8Array | number[], +} +export interface StreamingCallbackToken { + 'key' : Key, + 'sha256' : [] | [Uint8Array | number[]], + 'index' : bigint, + 'content_encoding' : string, +} +export type StreamingStrategy = { + 'Callback' : { + 'token' : StreamingCallbackToken, + 'callback' : [Principal, string], + } + }; +export type Time = bigint; +export interface UnsetAssetContentArguments { + 'key' : Key, + 'content_encoding' : string, +} +export interface UpgradeArgs { 'set_permissions' : [] | [SetPermissions] } +export type ValidationResult = { 'Ok' : string } | + { 'Err' : string }; +export interface _SERVICE { + 'api_version' : ActorMethod<[], number>, + 'authorize' : ActorMethod<[Principal], undefined>, + 'certified_tree' : ActorMethod< + [{}], + { 'certificate' : Uint8Array | number[], 'tree' : Uint8Array | number[] } + >, + 'clear' : ActorMethod<[ClearArguments], undefined>, + 'commit_batch' : ActorMethod<[CommitBatchArguments], undefined>, + 'commit_proposed_batch' : ActorMethod< + [CommitProposedBatchArguments], + undefined + >, + 'compute_evidence' : ActorMethod< + [ComputeEvidenceArguments], + [] | [Uint8Array | number[]] + >, + 'configure' : ActorMethod<[ConfigureArguments], undefined>, + 'create_asset' : ActorMethod<[CreateAssetArguments], undefined>, + 'create_batch' : ActorMethod<[{}], { 'batch_id' : BatchId }>, + 'create_chunk' : ActorMethod< + [{ 'content' : Uint8Array | number[], 'batch_id' : BatchId }], + { 'chunk_id' : ChunkId } + >, + 'deauthorize' : ActorMethod<[Principal], undefined>, + 'delete_asset' : ActorMethod<[DeleteAssetArguments], undefined>, + 'delete_batch' : ActorMethod<[DeleteBatchArguments], undefined>, + 'get' : ActorMethod< + [{ 'key' : Key, 'accept_encodings' : Array }], + { + 'content' : Uint8Array | number[], + 'sha256' : [] | [Uint8Array | number[]], + 'content_type' : string, + 'content_encoding' : string, + 'total_length' : bigint, + } + >, + 'get_asset_properties' : ActorMethod< + [Key], + { + 'headers' : [] | [Array], + 'is_aliased' : [] | [boolean], + 'allow_raw_access' : [] | [boolean], + 'max_age' : [] | [bigint], + } + >, + 'get_chunk' : ActorMethod< + [ + { + 'key' : Key, + 'sha256' : [] | [Uint8Array | number[]], + 'index' : bigint, + 'content_encoding' : string, + }, + ], + { 'content' : Uint8Array | number[] } + >, + 'get_configuration' : ActorMethod<[], ConfigurationResponse>, + 'grant_permission' : ActorMethod<[GrantPermission], undefined>, + 'http_request' : ActorMethod<[HttpRequest], HttpResponse>, + 'http_request_streaming_callback' : ActorMethod< + [StreamingCallbackToken], + [] | [StreamingCallbackHttpResponse] + >, + 'list' : ActorMethod< + [{}], + Array< + { + 'key' : Key, + 'encodings' : Array< + { + 'modified' : Time, + 'sha256' : [] | [Uint8Array | number[]], + 'length' : bigint, + 'content_encoding' : string, + } + >, + 'content_type' : string, + } + > + >, + 'list_authorized' : ActorMethod<[], Array>, + 'list_permitted' : ActorMethod<[ListPermitted], Array>, + 'propose_commit_batch' : ActorMethod<[CommitBatchArguments], undefined>, + 'revoke_permission' : ActorMethod<[RevokePermission], undefined>, + 'set_asset_content' : ActorMethod<[SetAssetContentArguments], undefined>, + 'set_asset_properties' : ActorMethod< + [SetAssetPropertiesArguments], + undefined + >, + 'store' : ActorMethod< + [ + { + 'key' : Key, + 'content' : Uint8Array | number[], + 'sha256' : [] | [Uint8Array | number[]], + 'content_type' : string, + 'content_encoding' : string, + }, + ], + undefined + >, + 'take_ownership' : ActorMethod<[], undefined>, + 'unset_asset_content' : ActorMethod<[UnsetAssetContentArguments], undefined>, + 'validate_commit_proposed_batch' : ActorMethod< + [CommitProposedBatchArguments], + ValidationResult + >, + 'validate_configure' : ActorMethod<[ConfigureArguments], ValidationResult>, + 'validate_grant_permission' : ActorMethod< + [GrantPermission], + ValidationResult + >, + 'validate_revoke_permission' : ActorMethod< + [RevokePermission], + ValidationResult + >, + 'validate_take_ownership' : ActorMethod<[], ValidationResult>, +} +export declare const idlFactory: IDL.InterfaceFactory; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/rust/image-classification/src/declarations/frontend/frontend.did.js b/rust/image-classification/src/declarations/frontend/frontend.did.js new file mode 100644 index 000000000..b68ea4a42 --- /dev/null +++ b/rust/image-classification/src/declarations/frontend/frontend.did.js @@ -0,0 +1,286 @@ +export const idlFactory = ({ IDL }) => { + const SetPermissions = IDL.Record({ + 'prepare' : IDL.Vec(IDL.Principal), + 'commit' : IDL.Vec(IDL.Principal), + 'manage_permissions' : IDL.Vec(IDL.Principal), + }); + const UpgradeArgs = IDL.Record({ + 'set_permissions' : IDL.Opt(SetPermissions), + }); + const InitArgs = IDL.Record({}); + const AssetCanisterArgs = IDL.Variant({ + 'Upgrade' : UpgradeArgs, + 'Init' : InitArgs, + }); + const ClearArguments = IDL.Record({}); + const BatchId = IDL.Nat; + const Key = IDL.Text; + const HeaderField = IDL.Tuple(IDL.Text, IDL.Text); + const SetAssetPropertiesArguments = IDL.Record({ + 'key' : Key, + 'headers' : IDL.Opt(IDL.Opt(IDL.Vec(HeaderField))), + 'is_aliased' : IDL.Opt(IDL.Opt(IDL.Bool)), + 'allow_raw_access' : IDL.Opt(IDL.Opt(IDL.Bool)), + 'max_age' : IDL.Opt(IDL.Opt(IDL.Nat64)), + }); + const CreateAssetArguments = IDL.Record({ + 'key' : Key, + 'content_type' : IDL.Text, + 'headers' : IDL.Opt(IDL.Vec(HeaderField)), + 'allow_raw_access' : IDL.Opt(IDL.Bool), + 'max_age' : IDL.Opt(IDL.Nat64), + 'enable_aliasing' : IDL.Opt(IDL.Bool), + }); + const UnsetAssetContentArguments = IDL.Record({ + 'key' : Key, + 'content_encoding' : IDL.Text, + }); + const DeleteAssetArguments = IDL.Record({ 'key' : Key }); + const ChunkId = IDL.Nat; + const SetAssetContentArguments = IDL.Record({ + 'key' : Key, + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'chunk_ids' : IDL.Vec(ChunkId), + 'content_encoding' : IDL.Text, + }); + const BatchOperationKind = IDL.Variant({ + 'SetAssetProperties' : SetAssetPropertiesArguments, + 'CreateAsset' : CreateAssetArguments, + 'UnsetAssetContent' : UnsetAssetContentArguments, + 'DeleteAsset' : DeleteAssetArguments, + 'SetAssetContent' : SetAssetContentArguments, + 'Clear' : ClearArguments, + }); + const CommitBatchArguments = IDL.Record({ + 'batch_id' : BatchId, + 'operations' : IDL.Vec(BatchOperationKind), + }); + const CommitProposedBatchArguments = IDL.Record({ + 'batch_id' : BatchId, + 'evidence' : IDL.Vec(IDL.Nat8), + }); + const ComputeEvidenceArguments = IDL.Record({ + 'batch_id' : BatchId, + 'max_iterations' : IDL.Opt(IDL.Nat16), + }); + const ConfigureArguments = IDL.Record({ + 'max_batches' : IDL.Opt(IDL.Opt(IDL.Nat64)), + 'max_bytes' : IDL.Opt(IDL.Opt(IDL.Nat64)), + 'max_chunks' : IDL.Opt(IDL.Opt(IDL.Nat64)), + }); + const DeleteBatchArguments = IDL.Record({ 'batch_id' : BatchId }); + const ConfigurationResponse = IDL.Record({ + 'max_batches' : IDL.Opt(IDL.Nat64), + 'max_bytes' : IDL.Opt(IDL.Nat64), + 'max_chunks' : IDL.Opt(IDL.Nat64), + }); + const Permission = IDL.Variant({ + 'Prepare' : IDL.Null, + 'ManagePermissions' : IDL.Null, + 'Commit' : IDL.Null, + }); + const GrantPermission = IDL.Record({ + 'permission' : Permission, + 'to_principal' : IDL.Principal, + }); + const HttpRequest = IDL.Record({ + 'url' : IDL.Text, + 'method' : IDL.Text, + 'body' : IDL.Vec(IDL.Nat8), + 'headers' : IDL.Vec(HeaderField), + 'certificate_version' : IDL.Opt(IDL.Nat16), + }); + const StreamingCallbackToken = IDL.Record({ + 'key' : Key, + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'index' : IDL.Nat, + 'content_encoding' : IDL.Text, + }); + const StreamingCallbackHttpResponse = IDL.Record({ + 'token' : IDL.Opt(StreamingCallbackToken), + 'body' : IDL.Vec(IDL.Nat8), + }); + const StreamingStrategy = IDL.Variant({ + 'Callback' : IDL.Record({ + 'token' : StreamingCallbackToken, + 'callback' : IDL.Func( + [StreamingCallbackToken], + [IDL.Opt(StreamingCallbackHttpResponse)], + ['query'], + ), + }), + }); + const HttpResponse = IDL.Record({ + 'body' : IDL.Vec(IDL.Nat8), + 'headers' : IDL.Vec(HeaderField), + 'streaming_strategy' : IDL.Opt(StreamingStrategy), + 'status_code' : IDL.Nat16, + }); + const Time = IDL.Int; + const ListPermitted = IDL.Record({ 'permission' : Permission }); + const RevokePermission = IDL.Record({ + 'permission' : Permission, + 'of_principal' : IDL.Principal, + }); + const ValidationResult = IDL.Variant({ 'Ok' : IDL.Text, 'Err' : IDL.Text }); + return IDL.Service({ + 'api_version' : IDL.Func([], [IDL.Nat16], ['query']), + 'authorize' : IDL.Func([IDL.Principal], [], []), + 'certified_tree' : IDL.Func( + [IDL.Record({})], + [ + IDL.Record({ + 'certificate' : IDL.Vec(IDL.Nat8), + 'tree' : IDL.Vec(IDL.Nat8), + }), + ], + ['query'], + ), + 'clear' : IDL.Func([ClearArguments], [], []), + 'commit_batch' : IDL.Func([CommitBatchArguments], [], []), + 'commit_proposed_batch' : IDL.Func([CommitProposedBatchArguments], [], []), + 'compute_evidence' : IDL.Func( + [ComputeEvidenceArguments], + [IDL.Opt(IDL.Vec(IDL.Nat8))], + [], + ), + 'configure' : IDL.Func([ConfigureArguments], [], []), + 'create_asset' : IDL.Func([CreateAssetArguments], [], []), + 'create_batch' : IDL.Func( + [IDL.Record({})], + [IDL.Record({ 'batch_id' : BatchId })], + [], + ), + 'create_chunk' : IDL.Func( + [IDL.Record({ 'content' : IDL.Vec(IDL.Nat8), 'batch_id' : BatchId })], + [IDL.Record({ 'chunk_id' : ChunkId })], + [], + ), + 'deauthorize' : IDL.Func([IDL.Principal], [], []), + 'delete_asset' : IDL.Func([DeleteAssetArguments], [], []), + 'delete_batch' : IDL.Func([DeleteBatchArguments], [], []), + 'get' : IDL.Func( + [IDL.Record({ 'key' : Key, 'accept_encodings' : IDL.Vec(IDL.Text) })], + [ + IDL.Record({ + 'content' : IDL.Vec(IDL.Nat8), + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'content_type' : IDL.Text, + 'content_encoding' : IDL.Text, + 'total_length' : IDL.Nat, + }), + ], + ['query'], + ), + 'get_asset_properties' : IDL.Func( + [Key], + [ + IDL.Record({ + 'headers' : IDL.Opt(IDL.Vec(HeaderField)), + 'is_aliased' : IDL.Opt(IDL.Bool), + 'allow_raw_access' : IDL.Opt(IDL.Bool), + 'max_age' : IDL.Opt(IDL.Nat64), + }), + ], + ['query'], + ), + 'get_chunk' : IDL.Func( + [ + IDL.Record({ + 'key' : Key, + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'index' : IDL.Nat, + 'content_encoding' : IDL.Text, + }), + ], + [IDL.Record({ 'content' : IDL.Vec(IDL.Nat8) })], + ['query'], + ), + 'get_configuration' : IDL.Func([], [ConfigurationResponse], []), + 'grant_permission' : IDL.Func([GrantPermission], [], []), + 'http_request' : IDL.Func([HttpRequest], [HttpResponse], ['query']), + 'http_request_streaming_callback' : IDL.Func( + [StreamingCallbackToken], + [IDL.Opt(StreamingCallbackHttpResponse)], + ['query'], + ), + 'list' : IDL.Func( + [IDL.Record({})], + [ + IDL.Vec( + IDL.Record({ + 'key' : Key, + 'encodings' : IDL.Vec( + IDL.Record({ + 'modified' : Time, + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'length' : IDL.Nat, + 'content_encoding' : IDL.Text, + }) + ), + 'content_type' : IDL.Text, + }) + ), + ], + ['query'], + ), + 'list_authorized' : IDL.Func([], [IDL.Vec(IDL.Principal)], []), + 'list_permitted' : IDL.Func([ListPermitted], [IDL.Vec(IDL.Principal)], []), + 'propose_commit_batch' : IDL.Func([CommitBatchArguments], [], []), + 'revoke_permission' : IDL.Func([RevokePermission], [], []), + 'set_asset_content' : IDL.Func([SetAssetContentArguments], [], []), + 'set_asset_properties' : IDL.Func([SetAssetPropertiesArguments], [], []), + 'store' : IDL.Func( + [ + IDL.Record({ + 'key' : Key, + 'content' : IDL.Vec(IDL.Nat8), + 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'content_type' : IDL.Text, + 'content_encoding' : IDL.Text, + }), + ], + [], + [], + ), + 'take_ownership' : IDL.Func([], [], []), + 'unset_asset_content' : IDL.Func([UnsetAssetContentArguments], [], []), + 'validate_commit_proposed_batch' : IDL.Func( + [CommitProposedBatchArguments], + [ValidationResult], + [], + ), + 'validate_configure' : IDL.Func( + [ConfigureArguments], + [ValidationResult], + [], + ), + 'validate_grant_permission' : IDL.Func( + [GrantPermission], + [ValidationResult], + [], + ), + 'validate_revoke_permission' : IDL.Func( + [RevokePermission], + [ValidationResult], + [], + ), + 'validate_take_ownership' : IDL.Func([], [ValidationResult], []), + }); +}; +export const init = ({ IDL }) => { + const SetPermissions = IDL.Record({ + 'prepare' : IDL.Vec(IDL.Principal), + 'commit' : IDL.Vec(IDL.Principal), + 'manage_permissions' : IDL.Vec(IDL.Principal), + }); + const UpgradeArgs = IDL.Record({ + 'set_permissions' : IDL.Opt(SetPermissions), + }); + const InitArgs = IDL.Record({}); + const AssetCanisterArgs = IDL.Variant({ + 'Upgrade' : UpgradeArgs, + 'Init' : InitArgs, + }); + return [IDL.Opt(AssetCanisterArgs)]; +}; diff --git a/rust/image-classification/src/declarations/frontend/index.d.ts b/rust/image-classification/src/declarations/frontend/index.d.ts new file mode 100644 index 000000000..b55074358 --- /dev/null +++ b/rust/image-classification/src/declarations/frontend/index.d.ts @@ -0,0 +1,50 @@ +import type { + ActorSubclass, + HttpAgentOptions, + ActorConfig, + Agent, +} from "@dfinity/agent"; +import type { Principal } from "@dfinity/principal"; +import type { IDL } from "@dfinity/candid"; + +import { _SERVICE } from './frontend.did'; + +export declare const idlFactory: IDL.InterfaceFactory; +export declare const canisterId: string; + +export declare interface CreateActorOptions { + /** + * @see {@link Agent} + */ + agent?: Agent; + /** + * @see {@link HttpAgentOptions} + */ + agentOptions?: HttpAgentOptions; + /** + * @see {@link ActorConfig} + */ + actorOptions?: ActorConfig; +} + +/** + * Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister. + * @constructs {@link ActorSubClass} + * @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to + * @param {CreateActorOptions} options - see {@link CreateActorOptions} + * @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions + * @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent + * @see {@link HttpAgentOptions} + * @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor + * @see {@link ActorConfig} + */ +export declare const createActor: ( + canisterId: string | Principal, + options?: CreateActorOptions +) => ActorSubclass<_SERVICE>; + +/** + * Intialized Actor using default settings, ready to talk to a canister using its candid interface + * @constructs {@link ActorSubClass} + */ +export declare const frontend: ActorSubclass<_SERVICE>; diff --git a/rust/image-classification/src/declarations/frontend/index.js b/rust/image-classification/src/declarations/frontend/index.js new file mode 100644 index 000000000..c5e4ab186 --- /dev/null +++ b/rust/image-classification/src/declarations/frontend/index.js @@ -0,0 +1,42 @@ +import { Actor, HttpAgent } from "@dfinity/agent"; + +// Imports and re-exports candid interface +import { idlFactory } from "./frontend.did.js"; +export { idlFactory } from "./frontend.did.js"; + +/* CANISTER_ID is replaced by webpack based on node environment + * Note: canister environment variable will be standardized as + * process.env.CANISTER_ID_ + * beginning in dfx 0.15.0 + */ +export const canisterId = + process.env.CANISTER_ID_FRONTEND; + +export const createActor = (canisterId, options = {}) => { + const agent = options.agent || new HttpAgent({ ...options.agentOptions }); + + if (options.agent && options.agentOptions) { + console.warn( + "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." + ); + } + + // Fetch root key for certificate validation during development + if (process.env.DFX_NETWORK !== "ic") { + agent.fetchRootKey().catch((err) => { + console.warn( + "Unable to fetch root key. Check to ensure that your local replica is running" + ); + console.error(err); + }); + } + + // Creates an actor with using the candid interface and the HttpAgent + return Actor.createActor(idlFactory, { + agent, + canisterId, + ...options.actorOptions, + }); +}; + +export const frontend = canisterId ? createActor(canisterId) : undefined; diff --git a/rust/image-classification/src/frontend/assets/.ic-assets.json5 b/rust/image-classification/src/frontend/assets/.ic-assets.json5 new file mode 100644 index 000000000..8dc76d1ee --- /dev/null +++ b/rust/image-classification/src/frontend/assets/.ic-assets.json5 @@ -0,0 +1,56 @@ +[ + { + "match": "**/*", + "headers": { + // Security: The Content Security Policy (CSP) given below aims at working with many apps rather than providing maximal security. + // We recommend tightening the CSP for your specific application. Some recommendations are as follows: + // - Use the CSP Evaluator (https://csp-evaluator.withgoogle.com/) to validate the CSP you define. + // - Follow the “Strict CSP” recommendations (https://csp.withgoogle.com/docs/strict-csp.html). However, note that in the context of the IC, + // nonces cannot be used because the response bodies must be static to work well with HTTP asset certification. + // Thus, we recommend to include script hashes (in combination with strict-dynamic) in the CSP as described + // in https://csp.withgoogle.com/docs/faq.html in section “What if my site is static and I can't add nonces to scripts?”. + // See for example the II CSP (https://github.com/dfinity/internet-identity/blob/main/src/internet_identity/src/http.rs). + // - It is recommended to tighten the connect-src directive. With the current CSP configuration the browser can + // make requests to https://*.icp0.io, hence being able to call any canister via https://icp0.io/api/v2/canister/{canister-ID}. + // This could potentially be used in combination with another vulnerability (e.g. XSS) to exfiltrate private data. + // The developer can configure this policy to only allow requests to their specific canisters, + // e.g: connect-src 'self' https://icp-api.io/api/v2/canister/{my-canister-ID}, where {my-canister-ID} has the following format: aaaaa-aaaaa-aaaaa-aaaaa-aaa + // - It is recommended to configure style-src, style-src-elem and font-src directives with the resources your canister is going to use + // instead of using the wild card (*) option. Normally this will include 'self' but also other third party styles or fonts resources (e.g: https://fonts.googleapis.com or other CDNs) + + // Notes about the CSP below: + // - script-src 'unsafe-eval' is currently required because agent-js uses a WebAssembly module for the validation of bls signatures. + // There is currently no other way to allow execution of WebAssembly modules with CSP. + // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. + // - We added img-src data: because data: images are used often. + // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + + // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. + // To configure permissions go here https://www.permissionspolicy.com/ + "Permissions-Policy": "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), speaker-selection=(), conversion-measurement=(), focus-without-user-activation=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), sync-script=(), trust-token-redemption=(), window-placement=(), vertical-scroll=()", + + // Security: Mitigates clickjacking attacks. + // See: https://owasp.org/www-community/attacks/Clickjacking. + "X-Frame-Options": "DENY", + + // Security: Avoids forwarding referrer information to other origins. + // See: https://owasp.org/www-project-secure-headers/#referrer-policy. + "Referrer-Policy": "same-origin", + + // Security: Tells the user’s browser that it must always use HTTPS with your site. + // See: https://owasp.org/www-project-secure-headers/#http-strict-transport-security + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + + // Security: Prevents the browser from interpreting files as a different MIME type to what is specified in the Content-Type header. + // See: https://owasp.org/www-project-secure-headers/#x-content-type-options + "X-Content-Type-Options": "nosniff", + + // Security: Enables browser features to mitigate some of the XSS attacks. Note that it has to be in mode=block. + // See: https://owasp.org/www-community/attacks/xss/ + "X-XSS-Protection": "1; mode=block" + }, + // redirect all requests from .raw.icp0.io to .icp0.io (this redirection is the default) + "allow_raw_access": false + }, +] diff --git a/rust/image-classification/src/frontend/assets/default.png b/rust/image-classification/src/frontend/assets/default.png new file mode 100644 index 0000000000000000000000000000000000000000..f66f964cd28c689807414a0fcf87d9deaf1e8c29 GIT binary patch literal 62786 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 OK8{D-ekwl_nD7VrSXhw& literal 0 HcmV?d00001 diff --git a/rust/image-classification/src/frontend/assets/favicon.ico b/rust/image-classification/src/frontend/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..338fbf34cd80a1fd7d0c259aae42b566a56f7168 GIT binary patch literal 15406 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 A0{{R3 literal 0 HcmV?d00001 diff --git a/rust/image-classification/src/frontend/assets/loader.svg b/rust/image-classification/src/frontend/assets/loader.svg new file mode 100644 index 000000000..2d448f5d0 --- /dev/null +++ b/rust/image-classification/src/frontend/assets/loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rust/image-classification/src/frontend/assets/logo_transparent.png b/rust/image-classification/src/frontend/assets/logo_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..94b22ca99cd8d19bc61dc1df5f003f0f9d15e848 GIT binary patch literal 58988 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 z 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 literal 0 HcmV?d00001 diff --git a/rust/image-classification/src/frontend/assets/main.css b/rust/image-classification/src/frontend/assets/main.css new file mode 100644 index 000000000..ae094b249 --- /dev/null +++ b/rust/image-classification/src/frontend/assets/main.css @@ -0,0 +1,162 @@ +body { + font-family: monospace; +} + +form { + display: flex; + justify-content: center; + max-width: 80vw; + margin: auto; +} + +div { + display: flex; + max-width: 80vw; + flex-flow: column; + align-items: baseline; +} + +img { + max-width: 80vw; + border: 1px solid #555; +} + +.image { + margin-top: 10px; + border: 1px solid #555; + width: 300px; + height: 300px; + object-fit: cover +} + +.invisible { + visibility: hidden; +} + +h1 { + font-size: 100%; +} + +textarea { + margin-top: -20px; + max-width: 80vw; +} + +.option { + display: flex; + flex-flow: row; + justify-content: left; + align-items: center; +} + +.toggle-switch { + position: relative; + display: inline-block; + width: 42px; + height: 18px; +} + +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + border-radius: 18px; + transition: 0.4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 1px; + bottom: 1px; + background-color: white; + border-radius: 50%; + transition: 0.4s; +} + +input:checked+.slider { + background-color: #b11dbb; +} + +input:checked+.slider:before { + transform: translateX(24px); +} + +input.file { + display: none; +} + +.clickable { + cursor: pointer; +} + +.clean-button { + display: inline-block; + padding: 5px 10px; + border: 2px solid #a10dab; + border-radius: 4px; + background-color: #b11dbb; + color: #fff; + cursor: pointer; + text-decoration: none; + transition: background-color 0.2s, color 0.2s, border-color 0.2s; +} + +.clean-button:disabled { + background-color: #ccc; + border-color: #ccc; +} + +ul { + margin: 0px; +} + +li { + margin-top: 10px; +} + +@keyframes astrodance { + 0% { + transform: translate(-50%,-50%) rotate(-20deg) + } + + 50% { + transform: translate(-50%,-50%) rotate(10deg) + } + + to { + transform: translate(-50%,-50%) rotate(-20deg) + } +} + +img.loader { + width: 32px; + display: block; + left: 50%; + position: absolute; + -webkit-user-select: none; + user-select: none; + animation-name: astrodance; + animation-duration: 5s; + animation-iteration-count: infinite; + animation-timing-function: ease-in-out; + border: none; + background-color: transparent; + padding-top: 30px; +} + +#container { + margin-top: 20px; +} \ No newline at end of file diff --git a/rust/image-classification/src/frontend/src/.ic-assets.json5 b/rust/image-classification/src/frontend/src/.ic-assets.json5 new file mode 100644 index 000000000..8dc76d1ee --- /dev/null +++ b/rust/image-classification/src/frontend/src/.ic-assets.json5 @@ -0,0 +1,56 @@ +[ + { + "match": "**/*", + "headers": { + // Security: The Content Security Policy (CSP) given below aims at working with many apps rather than providing maximal security. + // We recommend tightening the CSP for your specific application. Some recommendations are as follows: + // - Use the CSP Evaluator (https://csp-evaluator.withgoogle.com/) to validate the CSP you define. + // - Follow the “Strict CSP” recommendations (https://csp.withgoogle.com/docs/strict-csp.html). However, note that in the context of the IC, + // nonces cannot be used because the response bodies must be static to work well with HTTP asset certification. + // Thus, we recommend to include script hashes (in combination with strict-dynamic) in the CSP as described + // in https://csp.withgoogle.com/docs/faq.html in section “What if my site is static and I can't add nonces to scripts?”. + // See for example the II CSP (https://github.com/dfinity/internet-identity/blob/main/src/internet_identity/src/http.rs). + // - It is recommended to tighten the connect-src directive. With the current CSP configuration the browser can + // make requests to https://*.icp0.io, hence being able to call any canister via https://icp0.io/api/v2/canister/{canister-ID}. + // This could potentially be used in combination with another vulnerability (e.g. XSS) to exfiltrate private data. + // The developer can configure this policy to only allow requests to their specific canisters, + // e.g: connect-src 'self' https://icp-api.io/api/v2/canister/{my-canister-ID}, where {my-canister-ID} has the following format: aaaaa-aaaaa-aaaaa-aaaaa-aaa + // - It is recommended to configure style-src, style-src-elem and font-src directives with the resources your canister is going to use + // instead of using the wild card (*) option. Normally this will include 'self' but also other third party styles or fonts resources (e.g: https://fonts.googleapis.com or other CDNs) + + // Notes about the CSP below: + // - script-src 'unsafe-eval' is currently required because agent-js uses a WebAssembly module for the validation of bls signatures. + // There is currently no other way to allow execution of WebAssembly modules with CSP. + // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. + // - We added img-src data: because data: images are used often. + // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + + // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. + // To configure permissions go here https://www.permissionspolicy.com/ + "Permissions-Policy": "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), speaker-selection=(), conversion-measurement=(), focus-without-user-activation=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), sync-script=(), trust-token-redemption=(), window-placement=(), vertical-scroll=()", + + // Security: Mitigates clickjacking attacks. + // See: https://owasp.org/www-community/attacks/Clickjacking. + "X-Frame-Options": "DENY", + + // Security: Avoids forwarding referrer information to other origins. + // See: https://owasp.org/www-project-secure-headers/#referrer-policy. + "Referrer-Policy": "same-origin", + + // Security: Tells the user’s browser that it must always use HTTPS with your site. + // See: https://owasp.org/www-project-secure-headers/#http-strict-transport-security + "Strict-Transport-Security": "max-age=31536000; includeSubDomains", + + // Security: Prevents the browser from interpreting files as a different MIME type to what is specified in the Content-Type header. + // See: https://owasp.org/www-project-secure-headers/#x-content-type-options + "X-Content-Type-Options": "nosniff", + + // Security: Enables browser features to mitigate some of the XSS attacks. Note that it has to be in mode=block. + // See: https://owasp.org/www-community/attacks/xss/ + "X-XSS-Protection": "1; mode=block" + }, + // redirect all requests from .raw.icp0.io to .icp0.io (this redirection is the default) + "allow_raw_access": false + }, +] diff --git a/rust/image-classification/src/frontend/src/index.html b/rust/image-classification/src/frontend/src/index.html new file mode 100644 index 000000000..014236805 --- /dev/null +++ b/rust/image-classification/src/frontend/src/index.html @@ -0,0 +1,30 @@ + + + + + + + ICP image classification + + + + + + +
+
+

ICP image classification

+ + +
+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/rust/image-classification/src/frontend/src/index.js b/rust/image-classification/src/frontend/src/index.js new file mode 100644 index 000000000..2e8bc9368 --- /dev/null +++ b/rust/image-classification/src/frontend/src/index.js @@ -0,0 +1,105 @@ +import { backend } from "../../declarations/backend"; + +document.getElementById("classify").onclick = classify; +document.getElementById("file").onchange = onImageChange; + +// Calls the backend to perform image classification. +async function classify(event) { + event.preventDefault(); + + const button = event.target; + const message = document.getElementById("message"); + const loader = document.getElementById("loader"); + const img = document.getElementById("image"); + + button.disabled = true; + button.className = "clean-button invisible"; + message.innerText = "Computing..."; + loader.className = "loader"; + + try { + const blob = await resize(img); + const result = await backend.classify(new Uint8Array(blob)); + if (result.Ok) { + render(message, result.Ok); + } else { + throw result.Err; + } + } catch (err) { + message.innerText = "Failed to classify image: " + JSON.stringify(err); + } + loader.className = "loader invisible"; + + return false; +} + +// Resizes the given image to 224x224px and returns the resulting PNG blob. +async function resize(img) { + const canvas = document.createElement("canvas"); + canvas.width = 224; + canvas.height = 224; + let scale = Math.max(canvas.width / img.naturalWidth, canvas.height / img.naturalHeight); + let width = img.naturalWidth * scale; + let height = img.naturalHeight * scale; + let x = canvas.width / 2 - width / 2; + let y = canvas.height / 2 - height / 2; + const ctx = canvas.getContext("2d"); + if (ctx) { + ctx.drawImage(img, x, y, width, height); + } + let bytes = await serialize(canvas); + return bytes; +} + +// Serializes the given canvas into PNG image bytes. +function serialize(canvas) { + return new Promise((resolve) => canvas.toBlob((blob) => blob.arrayBuffer().then(resolve), "image/png", 0.9)); +} + +// Adds the classification results as a list to the given DOM element. +function render(element, classification) { + element.innerText = "Results:"; + let ul = document.createElement("ul"); + for (let item of classification) { + let li = document.createElement("li"); + let b = document.createElement("b"); + b.innerText = item.label.toLowerCase(); + let t = document.createTextNode("[score " + Math.round(item.score * 10) / 10 + "]"); + li.appendChild(b); + li.appendChild(t); + ul.appendChild(li) + } + element.appendChild(ul); +} + +// This function is called when the user selects a new image file. +async function onImageChange(event) { + const button = document.getElementById("classify"); + const message = document.getElementById("message"); + const img = document.getElementById("image"); + try { + const file = event.target.files[0]; + const url = await toDataURL(file); + img.src = url; + img.width = 600; + img.className = "image"; + } catch (err) { + message.innerText = "Failed to select image: " + err.toString(); + } + button.disabled = false; + button.className = "clean-button"; + message.innerText = ""; + return false; +} + +// Converts the given blob into a data url such that it can be assigned as a +// target of a link of as an image source. +function toDataURL(blob) { + return new Promise((resolve, _) => { + const fileReader = new FileReader(); + fileReader.readAsDataURL(blob); + fileReader.onloadend = function () { + resolve(fileReader.result); + } + }); +} diff --git a/rust/image-classification/webpack.config.js b/rust/image-classification/webpack.config.js new file mode 100644 index 000000000..4792c054a --- /dev/null +++ b/rust/image-classification/webpack.config.js @@ -0,0 +1,96 @@ +require("dotenv").config(); +const path = require("path"); +const webpack = require("webpack"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); +const CopyPlugin = require("copy-webpack-plugin"); + +const isDevelopment = process.env.NODE_ENV !== "production"; + +const frontendDirectory = "frontend"; + +const frontend_entry = path.join("src", frontendDirectory, "src", "index.html"); + +module.exports = { + target: "web", + mode: isDevelopment ? "development" : "production", + entry: { + // The frontend.entrypoint points to the HTML file for this build, so we need + // to replace the extension to `.js`. + index: path.join(__dirname, frontend_entry).replace(/\.html$/, ".js"), + }, + devtool: isDevelopment ? "source-map" : false, + optimization: { + minimize: !isDevelopment, + minimizer: [new TerserPlugin()], + }, + resolve: { + extensions: [".js", ".ts", ".jsx", ".tsx"], + fallback: { + assert: require.resolve("assert/"), + buffer: require.resolve("buffer/"), + events: require.resolve("events/"), + stream: require.resolve("stream-browserify/"), + util: require.resolve("util/"), + }, + }, + output: { + filename: "index.js", + path: path.join(__dirname, "dist", frontendDirectory), + }, + + // Depending in the language or framework you are using for + // front-end development, add module loaders to the default + // webpack configuration. For example, if you are using React + // modules and CSS as described in the "Adding a stylesheet" + // tutorial, uncomment the following lines: + // module: { + // rules: [ + // { test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" }, + // { test: /\.css$/, use: ['style-loader','css-loader'] } + // ] + // }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.join(__dirname, frontend_entry), + cache: false, + }), + new webpack.EnvironmentPlugin([ + ...Object.keys(process.env).filter((key) => { + if (key.includes("CANISTER")) return true; + if (key.includes("DFX")) return true; + return false; + }), + ]), + new webpack.ProvidePlugin({ + Buffer: [require.resolve("buffer/"), "Buffer"], + process: require.resolve("process/browser"), + }), + new CopyPlugin({ + patterns: [ + { + from: `src/${frontendDirectory}/src/.ic-assets.json*`, + to: ".ic-assets.json5", + noErrorOnMissing: true, + }, + ], + }), + ], + // proxy /api to port 4943 during development. + // if you edit dfx.json to define a project-specific local network, change the port to match. + devServer: { + proxy: { + "/api": { + target: "http://127.0.0.1:4943", + changeOrigin: true, + pathRewrite: { + "^/api": "/api", + }, + }, + }, + static: path.resolve(__dirname, "src", frontendDirectory, "assets"), + hot: true, + watchFiles: [path.resolve(__dirname, "src", frontendDirectory)], + liveReload: true, + }, +};