From 064899f740ef7e1811f3b53e46b28f0ebe11d37b Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Thu, 4 Jul 2024 14:12:51 +0200 Subject: [PATCH 1/9] Add a face recognition example in Rust --- rust/face-recognition/.cargo/config.toml | 5 + rust/face-recognition/.gitignore | 13 + rust/face-recognition/Cargo.lock | 1756 +++++++ rust/face-recognition/Cargo.toml | 3 + rust/face-recognition/Makefile | 34 + rust/face-recognition/README.md | 100 + rust/face-recognition/build.sh | 8 + rust/face-recognition/dfx.json | 37 + .../download-face-detection-model.sh | 20 + rust/face-recognition/package-lock.json | 4579 +++++++++++++++++ rust/face-recognition/package.json | 48 + rust/face-recognition/rust-toolchain.toml | 4 + rust/face-recognition/src/backend/Cargo.toml | 22 + .../src/backend/assets/image.png | Bin 0 -> 61197 bytes .../src/backend/assets/logo_transparent.png | Bin 0 -> 58988 bytes rust/face-recognition/src/backend/backend.did | 51 + .../src/backend/src/benchmarking.rs | 43 + rust/face-recognition/src/backend/src/lib.rs | 143 + rust/face-recognition/src/backend/src/onnx.rs | 181 + .../src/backend/src/storage.rs | 20 + .../src/declarations/backend/backend.did | 51 + .../src/declarations/backend/backend.did.d.ts | 39 + .../src/declarations/backend/backend.did.js | 31 + .../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 | 120 + .../src/frontend/src/.ic-assets.json5 | 56 + .../src/frontend/src/index.html | 41 + .../src/frontend/src/index.js | 266 + .../upload-models-to-canister.sh | 8 + rust/face-recognition/webpack.config.js | 96 + 41 files changed, 8804 insertions(+) create mode 100644 rust/face-recognition/.cargo/config.toml create mode 100644 rust/face-recognition/.gitignore create mode 100644 rust/face-recognition/Cargo.lock create mode 100644 rust/face-recognition/Cargo.toml create mode 100644 rust/face-recognition/Makefile create mode 100644 rust/face-recognition/README.md create mode 100755 rust/face-recognition/build.sh create mode 100644 rust/face-recognition/dfx.json create mode 100755 rust/face-recognition/download-face-detection-model.sh create mode 100644 rust/face-recognition/package-lock.json create mode 100644 rust/face-recognition/package.json create mode 100644 rust/face-recognition/rust-toolchain.toml create mode 100644 rust/face-recognition/src/backend/Cargo.toml create mode 100644 rust/face-recognition/src/backend/assets/image.png create mode 100644 rust/face-recognition/src/backend/assets/logo_transparent.png create mode 100644 rust/face-recognition/src/backend/backend.did create mode 100644 rust/face-recognition/src/backend/src/benchmarking.rs create mode 100644 rust/face-recognition/src/backend/src/lib.rs create mode 100644 rust/face-recognition/src/backend/src/onnx.rs create mode 100644 rust/face-recognition/src/backend/src/storage.rs create mode 100644 rust/face-recognition/src/declarations/backend/backend.did create mode 100644 rust/face-recognition/src/declarations/backend/backend.did.d.ts create mode 100644 rust/face-recognition/src/declarations/backend/backend.did.js create mode 100644 rust/face-recognition/src/declarations/backend/index.d.ts create mode 100644 rust/face-recognition/src/declarations/backend/index.js create mode 100644 rust/face-recognition/src/declarations/frontend/frontend.did create mode 100644 rust/face-recognition/src/declarations/frontend/frontend.did.d.ts create mode 100644 rust/face-recognition/src/declarations/frontend/frontend.did.js create mode 100644 rust/face-recognition/src/declarations/frontend/index.d.ts create mode 100644 rust/face-recognition/src/declarations/frontend/index.js create mode 100644 rust/face-recognition/src/frontend/assets/.ic-assets.json5 create mode 100644 rust/face-recognition/src/frontend/assets/default.png create mode 100644 rust/face-recognition/src/frontend/assets/favicon.ico create mode 100644 rust/face-recognition/src/frontend/assets/loader.svg create mode 100644 rust/face-recognition/src/frontend/assets/logo_transparent.png create mode 100644 rust/face-recognition/src/frontend/assets/main.css create mode 100644 rust/face-recognition/src/frontend/src/.ic-assets.json5 create mode 100644 rust/face-recognition/src/frontend/src/index.html create mode 100644 rust/face-recognition/src/frontend/src/index.js create mode 100755 rust/face-recognition/upload-models-to-canister.sh create mode 100644 rust/face-recognition/webpack.config.js diff --git a/rust/face-recognition/.cargo/config.toml b/rust/face-recognition/.cargo/config.toml new file mode 100644 index 000000000..067cfd27d --- /dev/null +++ b/rust/face-recognition/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = ["wasm32-wasi"] + +[target.wasm32-wasi] +rustflags = ["-Ctarget-feature=+simd128"] diff --git a/rust/face-recognition/.gitignore b/rust/face-recognition/.gitignore new file mode 100644 index 000000000..c3ed99af2 --- /dev/null +++ b/rust/face-recognition/.gitignore @@ -0,0 +1,13 @@ +.dfx/ +build/ +node_modules/ +dist/ +.DS_Store +_MACOSX +.vscode/ +target/ +*.old.did +.idea +src/backend/assets/version-RFB-320.onnx +src/backend/assets/facerec.onnx +.env diff --git a/rust/face-recognition/Cargo.lock b/rust/face-recognition/Cargo.lock new file mode 100644 index 000000000..87b2265e5 --- /dev/null +++ b/rust/face-recognition/Cargo.lock @@ -0,0 +1,1756 @@ +# 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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backend" +version = "1.1.0" +dependencies = [ + "anyhow", + "bytes", + "candid", + "colorgrad", + "ic-cdk 0.14.0", + "ic-stable-structures", + "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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[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.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "candid" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5902d37352dffd8bd9177a2daa6444ce3cd0279c91763fb0171c053aa04335" +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.66", +] + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[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 = "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[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.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "dyn-hash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a650a461c6a8ff1ef205ed9a2ad56579309853fecefc2423f73dced342f92258" + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +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.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +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.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8859bc2b863a77750acf199e1fb7e3fc403e1b475855ba13f59cb4e4036d238" +dependencies = [ + "candid", + "ic-cdk-macros 0.13.2", + "ic0 0.21.1", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-cdk" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff384f182459bec490a7f50a58bbdf8f7a6934de4dcc259e30c70641bcbcb917" +dependencies = [ + "candid", + "ic-cdk-macros 0.14.0", + "ic0 0.23.0", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45800053d80a6df839a71aaea5797e723188c0b992618208ca3b941350c7355" +dependencies = [ + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream 0.1.7", + "syn 1.0.109", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01dc6bc425ec048d6ac4137c7c0f2cfbd6f8b0be8efc568feae2b265f566117c" +dependencies = [ + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream 0.2.1", + "syn 2.0.66", +] + +[[package]] +name = "ic-stable-structures" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f3044466a69802de74e710dc0300b706a05696a0531c942ca856751a13b0db" +dependencies = [ + "ic_principal", +] + +[[package]] +name = "ic-wasi-polyfill" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1617b3be6bc1a4c854fbd86dc97dea3ff4461f70b5c4e95cf895dbc089dac51b" +dependencies = [ + "function_name", + "ic-cdk 0.13.2", + "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 = "ic0" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de254dd67bbd58073e23dc1c8553ba12fa1dc610a19de94ad2bbcd0460c067f" + +[[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.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[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.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "liquid" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10929f201279ba14da3297b957dcda1e0bf7a6f3bb5115688be684aa8864e9cc" +dependencies = [ + "doc-comment", + "liquid-core", + "liquid-derive", + "liquid-lib", + "serde", +] + +[[package]] +name = "liquid-core" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aef4b2160791f456eb880c990a97746f693746f92302ef5f1d06111cf14b768" +dependencies = [ + "anymap2", + "itertools 0.12.1", + "kstring", + "liquid-derive", + "num-traits", + "pest", + "pest_derive", + "regex", + "serde", + "time", +] + +[[package]] +name = "liquid-derive" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915f6d0a2963a27cd5205c1902f32ddfe3bc035816afd268cf88c0fc0f8d287e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "liquid-lib" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f48fc446873f74d869582f5c4b8cbf3248c93395e410a67af5809b3731e44a" +dependencies = [ + "itertools 0.12.1", + "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +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.66", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" +dependencies = [ + "num-integer", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +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.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +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 = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[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.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[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.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +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.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[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 = "serde_tokenstream" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8790a7c3fe883e443eaa2af6f705952bc5d6e8671a220b9335c8cae92c037e74" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.66", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable-fs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fefe75766646a3c7de5ec64e646d775cb2f59e736bb703e44a5fd0cfc6e87bc7" +dependencies = [ + "bitflags 2.5.0", + "ciborium", + "ic-cdk 0.13.2", + "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.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +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.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +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.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +dependencies = [ + "anyhow", + "downcast-rs", + "dyn-hash", + "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.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +dependencies = [ + "derive-new", + "log", + "tract-core", +] + +[[package]] +name = "tract-linalg" +version = "0.21.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +dependencies = [ + "cc", + "derive-new", + "downcast-rs", + "dyn-clone", + "dyn-hash", + "half", + "lazy_static", + "liquid", + "liquid-core", + "log", + "num-traits", + "paste", + "rayon", + "scan_fmt", + "smallvec", + "time", + "tract-data", + "unicode-normalization", + "walkdir", +] + +[[package]] +name = "tract-nnef" +version = "0.21.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +dependencies = [ + "byteorder", + "flate2", + "log", + "nom", + "tar", + "tract-core", + "walkdir", +] + +[[package]] +name = "tract-onnx" +version = "0.21.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +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.6-pre" +source = "git+https://github.com/sonos/tract?rev=2a2914ac29390cc08963301c9f3d437b52dd321a#2a2914ac29390cc08963301c9f3d437b52dd321a" +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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[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.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] diff --git a/rust/face-recognition/Cargo.toml b/rust/face-recognition/Cargo.toml new file mode 100644 index 000000000..4c16df46e --- /dev/null +++ b/rust/face-recognition/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["src/backend"] +resolver = "2" diff --git a/rust/face-recognition/Makefile b/rust/face-recognition/Makefile new file mode 100644 index 000000000..2745358b1 --- /dev/null +++ b/rust/face-recognition/Makefile @@ -0,0 +1,34 @@ +.PHONY: all +all: build + +.PHONY: node_modules +.SILENT: node_modules +node_modules: + npm install + +.PHONY: build +.SILENT: build +build: node_modules + dfx canister create --all + dfx build + +.PHONY: install +.SILENT: install +install: build + dfx deploy --yes + +.PHONY: upgrade +.SILENT: upgrade +upgrade: build + dfx canister install --all --mode=upgrade + +.PHONY: test +.SILENT: test +test: install + dfx canister call backend run_detection | grep -w 'top = 0.15649638' && echo 'PASS' + dfx canister call backend run_recognition | grep -w 'Unknown person' && echo 'PASS' + +.PHONY: clean +.SILENT: clean +clean: + rm -fr .dfx diff --git a/rust/face-recognition/README.md b/rust/face-recognition/README.md new file mode 100644 index 000000000..6e817a421 --- /dev/null +++ b/rust/face-recognition/README.md @@ -0,0 +1,100 @@ +# ICP Face Recognition + +This is an ICP smart contract runs face detection and face recognition of user's photo that can be uploaded either from a camera or a local file. + +The smart contract consists of two canisters: + +- the backend canister embeds the [the Tract ONNX inference engine](https://github.com/sonos/tract) with two ONNX models. One model is used to detect a face in the photo and return its bounding box. Another model is used for computing face embeddings. +- the frontend canister contains the Web assets such as HTML, JS, CSS that are served to the browser. + +# Models + +The smart contract uses two models: one for detecting the face and another for recognizing the face. + +## Face detection + +A face detection model finds the bounding box of a face in the image. +You can download [Ultraface](https://github.com/onnx/models/tree/main/validated/vision/body_analysis/ultraface) - ultra-lightweight face detection model - [[here](https://github.com/onnx/models/blob/bec48b6a70e5e9042c0badbaafefe4454e072d08/validated/vision/body_analysis/ultraface/models/version-RFB-320.onnx)]. + +Alternatively, you can run +``` +./download-face-detection-model.sh +``` + +## Face recognition + +A face recognition model computes a vector embedding of an image with a face. +You can obtain a pretrained model from [facenet-pytorch](https://github.com/timesler/facenet-pytorch) as follows. + + +1. Install `python` and `pip`: https://packaging.python.org/en/latest/tutorials/installing-packages/. + +2. Install `facenet-pytorch` and `torch`: +``` +pip install facenet-pytorch +pip install torch +pip install onnx +``` + +3. Export ONNX model. Start a python shell and run the following commands or create a python file and run it: +``` +import torch +import facenet_pytorch +resnet = facenet_pytorch.InceptionResnetV1(pretrained='vggface2').eval() +input = torch.randn(1, 3, 160, 160) +torch.onnx.export(resnet, input, "face-recognition.onnx", verbose=False, opset_version=11) +``` + +4. This should produce `face-recognition.onnx`. Copy the file to the root of this repository. + +# Dependencies + +Install `dfx`, Rust, etc: https://internetcomputer.org/docs/current/developer-docs/getting-started/hello-world + +Install `wasi2ic`: +- Follow the steps in https://github.com/wasm-forge/wasi2ic +- Make sure that `wasi2ic` binary is in your `$PATH`. + +Install NodeJS dependencies for the frontend: + +``` +npm install +``` + +Install `wasm-opt`: + +``` +cargo install wasm-opt +``` + +# Build + +``` +dfx start --background +dfx deploy +``` + +If the deployment is successful, the it will show the `frontend` URL. +Open that URL in browser to interact with the smart contract. + +# Chunk uploading of models + +Since the models are large, they cannot be embedded into the Wasm binary of the smart contract. +Instead they should be uploaded separately. + +[DecideAI](https://decideai.xyz/) implemented a tool for incremental uploading of models: https://github.com/modclub-app/rust-connect-py-ai-to-ic/tree/main/rust/upload_multiple_byte_files. + +In order to upload the models, you need to clone that repository, build the `upload_byte_file` rust binary, and add it to your `$PATH`. +Afterwards, execute the `upload-models-to-canister.sh` script, which runs the following commands: +``` +dfx canister call backend clear_face_detection_model_bytes +dfx canister call backend clear_face_recognition_model_bytes +upload_byte_file backend append_face_detection_model_bytes . version-RFB-320.onnx +upload_byte_file backend append_face_recognition_model_bytes . face-recognition.onnx +dfx canister call backend setup_models +``` + +# Credits + +Thanks to [DecideAI](https://decideai.xyz/) for discussions and providing [rust-connect-py-ai-to-ic](https://github.com/modclub-app/rust-connect-py-ai-to-ic/tree/main/rust/upload_multiple_byte_files). + diff --git a/rust/face-recognition/build.sh b/rust/face-recognition/build.sh new file mode 100755 index 000000000..157830603 --- /dev/null +++ b/rust/face-recognition/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ex + +export RUSTFLAGS=$RUSTFLAGS' -C target-feature=+simd128' +cargo build --release --target=wasm32-wasi +wasi2ic ./target/wasm32-wasi/release/backend.wasm ./target/wasm32-wasi/release/backend-ic.wasm +wasm-opt -Os --enable-simd --enable-bulk-memory -o ./target/wasm32-wasi/release/backend-ic.wasm \ + ./target/wasm32-wasi/release/backend-ic.wasm diff --git a/rust/face-recognition/dfx.json b/rust/face-recognition/dfx.json new file mode 100644 index 000000000..e5ee40ef0 --- /dev/null +++ b/rust/face-recognition/dfx.json @@ -0,0 +1,37 @@ +{ + "canisters": { + "backend": { + "metadata": [ + { + "name": "candid:service" + } + ], + "candid": "src/backend/backend.did", + "package": "backend", + "type": "custom", + "wasm": "target/wasm32-wasi/release/backend-ic.wasm", + "build": [ "bash build.sh" ] + }, + "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 +} \ No newline at end of file diff --git a/rust/face-recognition/download-face-detection-model.sh b/rust/face-recognition/download-face-detection-model.sh new file mode 100755 index 000000000..3aea8a061 --- /dev/null +++ b/rust/face-recognition/download-face-detection-model.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +ULTRAFACE_URL="https://github.com/onnx/models/raw/bec48b6a70e5e9042c0badbaafefe4454e072d08/validated/vision/body_analysis/ultraface/models/version-RFB-320.onnx" +ULTRAFACE_TGT="version-RFB-320.onnx" + +echo "Downloading ${ULTRAFACE_TGT}..." +if [ -s "${ULTRAFACE_TGT}" ]; then + echo " (cached)" + exit 0 +fi + +if which wget >/dev/null; then + wget $ULTRAFACE_URL -O $ULTRAFACE_TGT +elif which curl >/dev/null; then + curl -vL $ULTRAFACE_URL -o $ULTRAFACE_TGT +else + echo "Couldn't find wget or curl." + echo "Please download manually from \"$ULTRAFACE_URL\" and save the file in $ULTRAFACE_TGT." +fi diff --git a/rust/face-recognition/package-lock.json b/rust/face-recognition/package-lock.json new file mode 100644 index 000000000..2f510456c --- /dev/null +++ b/rust/face-recognition/package-lock.json @@ -0,0 +1,4579 @@ +{ + "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.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "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.2", + "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.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.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.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "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.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "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.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.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.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "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.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "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.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "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.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "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.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "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.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "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.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "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.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "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.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "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/face-recognition/package.json b/rust/face-recognition/package.json new file mode 100644 index 000000000..82bd21c99 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/rust-toolchain.toml b/rust/face-recognition/rust-toolchain.toml new file mode 100644 index 000000000..0ecadb670 --- /dev/null +++ b/rust/face-recognition/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.79" +targets = ["wasm32-unknown-unknown", "wasm32-wasi"] +components = ["rustfmt", "clippy"] diff --git a/rust/face-recognition/src/backend/Cargo.toml b/rust/face-recognition/src/backend/Cargo.toml new file mode 100644 index 000000000..bf9676ca0 --- /dev/null +++ b/rust/face-recognition/src/backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "backend" +version = "1.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0" +bytes = "1.5.0" +candid = "0.10" +colorgrad = "0.6" +ic-cdk = "0.14.0" +ic-stable-structures = "0.6" +ic-wasi-polyfill = "0.4.1" +image = { version = "0.25.1", features = ["png"], default-features = false } +prost = "0.11.0" +prost-types = "0.11.0" +serde = { version = "1.0", features = ["derive"] } +tract-onnx = { git = "https://github.com/sonos/tract", rev = "2a2914ac29390cc08963301c9f3d437b52dd321a" } + diff --git a/rust/face-recognition/src/backend/assets/image.png b/rust/face-recognition/src/backend/assets/image.png new file mode 100644 index 0000000000000000000000000000000000000000..f8b5d2c8a18f436cf1b00e4d921dd3b270adcc95 GIT binary patch literal 61197 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 Hu0mjfvX$wM literal 0 HcmV?d00001 diff --git a/rust/face-recognition/src/backend/assets/logo_transparent.png b/rust/face-recognition/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/face-recognition/src/backend/backend.did b/rust/face-recognition/src/backend/backend.did new file mode 100644 index 000000000..944ed2256 --- /dev/null +++ b/rust/face-recognition/src/backend/backend.did @@ -0,0 +1,51 @@ +type BoundingBox = record { + left: float32; + top: float32; + right: float32; + bottom: float32; +}; + +type Embedding = record { + v0: vec float32; +}; + +type Person = record { + label: text; + score: float32; +}; + +type Detection = variant { + Ok: BoundingBox; + Err: Error; +}; + +type Addition = variant { + Ok: Embedding; + Err: Error; +}; + +type Recognition = variant { + Ok: Person; + Err: Error; +}; + +type Error = record { + message: text; +}; + +service : { + "detect": (image: blob) -> (Detection) query; + "recognize": (image: blob) -> (Recognition); + "add": (label: text, image: blob) -> (Addition); + + // These endpoints are used for incremental uploading of model files. + "clear_face_detection_model_bytes": () -> (); + "clear_face_recognition_model_bytes": () -> (); + "append_face_detection_model_bytes": (bytes: blob) -> (); + "append_face_recognition_model_bytes": (bytes: blob) -> (); + "setup_models": () -> (); + + // These endpoints are used only for testing and benchmarking. + "run_detection": () -> (Detection) query; + "run_recognition": () -> (Recognition); +} \ No newline at end of file diff --git a/rust/face-recognition/src/backend/src/benchmarking.rs b/rust/face-recognition/src/backend/src/benchmarking.rs new file mode 100644 index 000000000..63373151b --- /dev/null +++ b/rust/face-recognition/src/backend/src/benchmarking.rs @@ -0,0 +1,43 @@ +// The code below is used for testing and benchmarking. + +use crate::{onnx, Detection, Error, Recognition}; + +const IMAGE: &'static [u8] = include_bytes!("../assets/image.png"); + +/// Formats thousands for the specified `u64` integer (helper function). +fn fmt(n: u64) -> String { + n.to_string() + .as_bytes() + .rchunks(3) + .rev() + .map(std::str::from_utf8) + .collect::, _>>() + .unwrap() + .join("_") +} + +#[ic_cdk::query] +fn run_detection() -> Detection { + let result = match onnx::detect(IMAGE.to_vec()) { + Ok(result) => Detection::Ok(result.0), + Err(err) => Detection::Err(Error { + message: err.to_string(), + }), + }; + let instructions = ic_cdk::api::performance_counter(0); + ic_cdk::println!("Executed instructions: {}", fmt(instructions)); + result +} + +#[ic_cdk::update] +fn run_recognition() -> Recognition { + let result = match onnx::recognize(IMAGE.to_vec()) { + Ok(result) => Recognition::Ok(result), + Err(err) => Recognition::Err(Error { + message: err.to_string(), + }), + }; + let instructions = ic_cdk::api::performance_counter(0); + ic_cdk::println!("Executed instructions: {}", fmt(instructions)); + result +} diff --git a/rust/face-recognition/src/backend/src/lib.rs b/rust/face-recognition/src/backend/src/lib.rs new file mode 100644 index 000000000..21202ee35 --- /dev/null +++ b/rust/face-recognition/src/backend/src/lib.rs @@ -0,0 +1,143 @@ +use candid::{CandidType, Deserialize}; +use ic_stable_structures::{ + memory_manager::{MemoryId, MemoryManager}, + DefaultMemoryImpl, +}; + +use onnx::{setup, BoundingBox, Embedding, Person}; +use std::cell::RefCell; + +mod benchmarking; +mod onnx; +mod storage; + +// WASI polyfill requires a virtual stable memory to store the file system. +// You can replace `0` with any index up to `254`. +const WASI_MEMORY_ID: MemoryId = MemoryId::new(0); + +// Files in the WASI filesystem (in the stable memory) that store the models. +const FACE_DETECTION_FILE: &str = "face-detection.onnx"; +const FACE_RECOGNITION_FILE: &str = "face-recognition.onnx"; + +thread_local! { + // The memory manager is used for simulating multiple memories. + static MEMORY_MANAGER: RefCell> = + RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); +} + +/// An error that is returned to the front-end. +#[derive(CandidType, Deserialize)] +struct Error { + message: String, +} + +/// The result of the face detection endpoint. +#[derive(CandidType, Deserialize)] +enum Detection { + Ok(BoundingBox), + Err(Error), +} + +/// The result of the face addition endpoint. +#[derive(CandidType, Deserialize)] +enum Addition { + Ok(Embedding), + Err(Error), +} + +/// The result of the face recognition endpoint. +#[derive(CandidType, Deserialize)] +enum Recognition { + Ok(Person), + Err(Error), +} + +/// Returns a bounding box around the detected face in the input image. +#[ic_cdk::query] +fn detect(image: Vec) -> Detection { + let result = match onnx::detect(image) { + Ok(result) => Detection::Ok(result.0), + Err(err) => Detection::Err(Error { + message: err.to_string(), + }), + }; + result +} + +/// Performs face recognition and returns the name of the person whose recorded +/// face is closest to the face in the given image. It also returns the distance +/// between the face embeddings. +#[ic_cdk::update] +fn recognize(image: Vec) -> Recognition { + let result = match onnx::recognize(image) { + Ok(result) => Recognition::Ok(result), + Err(err) => Recognition::Err(Error { + message: err.to_string(), + }), + }; + result +} + +/// Adds a person with the given name (label) and face (image) for future +/// face recognition requests. +#[ic_cdk::update] +fn add(label: String, image: Vec) -> Addition { + let result = match onnx::add(label, image) { + Ok(result) => Addition::Ok(result), + Err(err) => Addition::Err(Error { + message: err.to_string(), + }), + }; + result +} + +/// Clears the face detection model file. +/// This is used for incremental chunk uploading of large files. +#[ic_cdk::update] +fn clear_face_detection_model_bytes() { + storage::clear_bytes(FACE_DETECTION_FILE); +} + +/// Clears the face recognition model file. +/// This is used for incremental chunk uploading of large files. +#[ic_cdk::update] +fn clear_face_recognition_model_bytes() { + storage::clear_bytes(FACE_RECOGNITION_FILE); +} + +/// Appends the given chunk to the face detection model file. +/// This is used for incremental chunk uploading of large files. +#[ic_cdk::update] +fn append_face_detection_model_bytes(bytes: Vec) { + storage::append_bytes(FACE_DETECTION_FILE, bytes); +} + +/// Appends the given chunk to the face recognition model file. +/// This is used for incremental chunk uploading of large files. +#[ic_cdk::update] +fn append_face_recognition_model_bytes(bytes: Vec) { + storage::append_bytes(FACE_RECOGNITION_FILE, bytes); +} + +/// Once the model files have been incrementally uploaded, +/// this function loads them into in-memory models. +#[ic_cdk::update] +fn setup_models() -> Result<(), String> { + setup( + storage::bytes(FACE_DETECTION_FILE), + storage::bytes(FACE_RECOGNITION_FILE), + ) + .map_err(|err| format!("Failed to setup model: {}", err)) +} + +#[ic_cdk::init] +fn init() { + let wasi_memory = MEMORY_MANAGER.with(|m| m.borrow().get(WASI_MEMORY_ID)); + ic_wasi_polyfill::init_with_memory(&[0u8; 32], &[], wasi_memory); +} + +#[ic_cdk::post_upgrade] +fn post_upgrade() { + let wasi_memory = MEMORY_MANAGER.with(|m| m.borrow().get(WASI_MEMORY_ID)); + ic_wasi_polyfill::init_with_memory(&[0u8; 32], &[], wasi_memory); +} diff --git a/rust/face-recognition/src/backend/src/onnx.rs b/rust/face-recognition/src/backend/src/onnx.rs new file mode 100644 index 000000000..5cf0406a7 --- /dev/null +++ b/rust/face-recognition/src/backend/src/onnx.rs @@ -0,0 +1,181 @@ +use anyhow::anyhow; +use bytes::Bytes; +use candid::CandidType; +use prost::Message; +use serde::Deserialize; +use std::cell::RefCell; +use tract_ndarray::s; +use tract_onnx::prelude::*; + +// The maximum distance between face embeddings of the same person. +const THRESHOLD: f32 = 0.85; + +type Model = SimplePlan, Graph>>; + +thread_local! { + static FACE_DETECTION: RefCell> = RefCell::new(None); + static FACE_RECOGNITION: RefCell> = RefCell::new(None); + static DB: RefCell> = RefCell::new(vec![]); +} + +#[derive(CandidType, Deserialize, Clone)] +pub struct BoundingBox { + left: f32, + top: f32, + right: f32, + bottom: f32, +} + +impl BoundingBox { + fn new(raw: &[f32]) -> Self { + Self { + left: raw[0], + top: raw[1], + right: raw[2], + bottom: raw[3], + } + } +} + +#[derive(CandidType, Deserialize, Clone)] +pub struct Embedding { + v0: Vec, +} + +impl Embedding { + fn distance(&self, other: &Self) -> f32 { + let result: f32 = self + .v0 + .iter() + .zip(other.v0.iter()) + .map(|(a, b)| (a - b) * (a - b)) + .sum(); + result.sqrt() + } +} + +#[derive(CandidType, Deserialize)] +pub struct Person { + label: String, + score: f32, +} + +fn setup_facedetect(bytes: Bytes) -> TractResult<()> { + let proto: tract_onnx::pb::ModelProto = tract_onnx::pb::ModelProto::decode(bytes)?; + let ultraface = tract_onnx::onnx() + .model_for_proto_model(&proto)? + .into_optimized()? + .into_runnable()?; + FACE_DETECTION.with_borrow_mut(|m| { + *m = Some(ultraface); + }); + Ok(()) +} + +fn setup_facerec(bytes: Bytes) -> TractResult<()> { + let proto: tract_onnx::pb::ModelProto = tract_onnx::pb::ModelProto::decode(bytes)?; + let facerec = tract_onnx::onnx() + .model_for_proto_model(&proto)? + .into_optimized()? + .into_runnable()?; + FACE_RECOGNITION.with_borrow_mut(|m| { + *m = Some(facerec); + }); + Ok(()) +} + +pub fn setup(facedetect: Bytes, facerec: Bytes) -> TractResult<()> { + setup_facedetect(facedetect)?; + setup_facerec(facerec) +} + +/// Returns a bounding box around the face detected in the given image. +pub fn detect(image: Vec) -> Result<(BoundingBox, f32), anyhow::Error> { + FACE_DETECTION.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 320x240px. + let image = + image::imageops::resize(&image, 320, 240, ::image::imageops::FilterType::Triangle); + + 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, 240, 320), |(_, 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 confidences = result[0] + .to_array_view::()? + .slice(s![0, .., 1]) + .to_vec(); + + let boxes: Vec<_> = result[1].to_array_view::()?.iter().cloned().collect(); + let boxes: Vec<_> = boxes.chunks(4).map(BoundingBox::new).collect(); + let boxes: Vec<_> = boxes.iter().zip(confidences.iter()).collect(); + + let best = boxes + .iter() + .max_by(|a, b| a.1.partial_cmp(b.1).unwrap()) + .ok_or(anyhow!("No face detected"))?; + + let best = (best.0.clone(), best.1.clone()); + Ok(best) + }) +} + +/// Computes a face embedding corresponding to the given image of a face. +pub fn embedding(image: Vec) -> Result { + FACE_RECOGNITION.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 140x140px. + let image = + image::imageops::resize(&image, 160, 160, ::image::imageops::FilterType::Triangle); + + let tensor = tract_ndarray::Array4::from_shape_fn((1, 3, 160, 160), |(_, c, y, x)| { + image[(x as u32, y as u32)][c] as f32 / 255.0 + }); + + let result = model.run(tvec!(Tensor::from(tensor).into()))?; + + let v0 = result[0] + .to_array_view::()? + .into_iter() + .cloned() + .collect(); + + Ok(Embedding { v0 }) + }) +} + +/// Returns the person whose face embedding is the closest to the face embedding +/// of the given image. +pub fn recognize(image: Vec) -> Result { + let emb = embedding(image)?; + DB.with_borrow(|db| { + let emb = &emb; + let best = db + .iter() + .min_by(|a, b| f32::partial_cmp(&a.1.distance(emb), &b.1.distance(emb)).unwrap()); + let best = best.ok_or(anyhow!("Unknown person"))?.clone(); + let label = best.0; + let score = best.1.distance(emb); + if score > THRESHOLD { + return Err(anyhow!("Unknown person")); + } + Ok(Person { label, score }) + }) +} + +/// Records a new person with the given name and face image into the state. +pub fn add(label: String, image: Vec) -> Result { + let emb = embedding(image)?; + DB.with_borrow_mut(|db| { + db.push((label, emb.clone())); + }); + Ok(emb) +} diff --git a/rust/face-recognition/src/backend/src/storage.rs b/rust/face-recognition/src/backend/src/storage.rs new file mode 100644 index 000000000..b46a126f1 --- /dev/null +++ b/rust/face-recognition/src/backend/src/storage.rs @@ -0,0 +1,20 @@ +use bytes::Bytes; +use std::io::Write; + +pub fn bytes(filename: &str) -> Bytes { + std::fs::read(filename).unwrap().into() +} + +pub fn append_bytes(filename: &str, bytes: Vec) { + let mut file = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(filename) + .unwrap(); + file.write_all(&bytes).unwrap(); +} + +pub fn clear_bytes(filename: &str) { + // Don't fail if the file doesn't exist. + let _ = std::fs::remove_file(filename); +} diff --git a/rust/face-recognition/src/declarations/backend/backend.did b/rust/face-recognition/src/declarations/backend/backend.did new file mode 100644 index 000000000..944ed2256 --- /dev/null +++ b/rust/face-recognition/src/declarations/backend/backend.did @@ -0,0 +1,51 @@ +type BoundingBox = record { + left: float32; + top: float32; + right: float32; + bottom: float32; +}; + +type Embedding = record { + v0: vec float32; +}; + +type Person = record { + label: text; + score: float32; +}; + +type Detection = variant { + Ok: BoundingBox; + Err: Error; +}; + +type Addition = variant { + Ok: Embedding; + Err: Error; +}; + +type Recognition = variant { + Ok: Person; + Err: Error; +}; + +type Error = record { + message: text; +}; + +service : { + "detect": (image: blob) -> (Detection) query; + "recognize": (image: blob) -> (Recognition); + "add": (label: text, image: blob) -> (Addition); + + // These endpoints are used for incremental uploading of model files. + "clear_face_detection_model_bytes": () -> (); + "clear_face_recognition_model_bytes": () -> (); + "append_face_detection_model_bytes": (bytes: blob) -> (); + "append_face_recognition_model_bytes": (bytes: blob) -> (); + "setup_models": () -> (); + + // These endpoints are used only for testing and benchmarking. + "run_detection": () -> (Detection) query; + "run_recognition": () -> (Recognition); +} \ No newline at end of file diff --git a/rust/face-recognition/src/declarations/backend/backend.did.d.ts b/rust/face-recognition/src/declarations/backend/backend.did.d.ts new file mode 100644 index 000000000..17b40664b --- /dev/null +++ b/rust/face-recognition/src/declarations/backend/backend.did.d.ts @@ -0,0 +1,39 @@ +import type { Principal } from '@dfinity/principal'; +import type { ActorMethod } from '@dfinity/agent'; +import type { IDL } from '@dfinity/candid'; + +export type Addition = { 'Ok' : Embedding } | + { 'Err' : Error }; +export interface BoundingBox { + 'top' : number, + 'left' : number, + 'bottom' : number, + 'right' : number, +} +export type Detection = { 'Ok' : BoundingBox } | + { 'Err' : Error }; +export interface Embedding { 'v0' : Array } +export interface Error { 'message' : string } +export interface Person { 'label' : string, 'score' : number } +export type Recognition = { 'Ok' : Person } | + { 'Err' : Error }; +export interface _SERVICE { + 'add' : ActorMethod<[string, Uint8Array | number[]], Addition>, + 'append_face_detection_model_bytes' : ActorMethod< + [Uint8Array | number[]], + undefined + >, + 'append_face_recognition_model_bytes' : ActorMethod< + [Uint8Array | number[]], + undefined + >, + 'clear_face_detection_model_bytes' : ActorMethod<[], undefined>, + 'clear_face_recognition_model_bytes' : ActorMethod<[], undefined>, + 'detect' : ActorMethod<[Uint8Array | number[]], Detection>, + 'recognize' : ActorMethod<[Uint8Array | number[]], Recognition>, + 'run_detection' : ActorMethod<[], Detection>, + 'run_recognition' : ActorMethod<[], Recognition>, + 'setup_models' : ActorMethod<[], undefined>, +} +export declare const idlFactory: IDL.InterfaceFactory; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/rust/face-recognition/src/declarations/backend/backend.did.js b/rust/face-recognition/src/declarations/backend/backend.did.js new file mode 100644 index 000000000..d026c3663 --- /dev/null +++ b/rust/face-recognition/src/declarations/backend/backend.did.js @@ -0,0 +1,31 @@ +export const idlFactory = ({ IDL }) => { + const Embedding = IDL.Record({ 'v0' : IDL.Vec(IDL.Float32) }); + const Error = IDL.Record({ 'message' : IDL.Text }); + const Addition = IDL.Variant({ 'Ok' : Embedding, 'Err' : Error }); + const BoundingBox = IDL.Record({ + 'top' : IDL.Float32, + 'left' : IDL.Float32, + 'bottom' : IDL.Float32, + 'right' : IDL.Float32, + }); + const Detection = IDL.Variant({ 'Ok' : BoundingBox, 'Err' : Error }); + const Person = IDL.Record({ 'label' : IDL.Text, 'score' : IDL.Float32 }); + const Recognition = IDL.Variant({ 'Ok' : Person, 'Err' : Error }); + return IDL.Service({ + 'add' : IDL.Func([IDL.Text, IDL.Vec(IDL.Nat8)], [Addition], []), + 'append_face_detection_model_bytes' : IDL.Func([IDL.Vec(IDL.Nat8)], [], []), + 'append_face_recognition_model_bytes' : IDL.Func( + [IDL.Vec(IDL.Nat8)], + [], + [], + ), + 'clear_face_detection_model_bytes' : IDL.Func([], [], []), + 'clear_face_recognition_model_bytes' : IDL.Func([], [], []), + 'detect' : IDL.Func([IDL.Vec(IDL.Nat8)], [Detection], ['query']), + 'recognize' : IDL.Func([IDL.Vec(IDL.Nat8)], [Recognition], []), + 'run_detection' : IDL.Func([], [Detection], ['query']), + 'run_recognition' : IDL.Func([], [Recognition], []), + 'setup_models' : IDL.Func([], [], []), + }); +}; +export const init = ({ IDL }) => { return []; }; diff --git a/rust/face-recognition/src/declarations/backend/index.d.ts b/rust/face-recognition/src/declarations/backend/index.d.ts new file mode 100644 index 000000000..55daa14e7 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/backend/index.js b/rust/face-recognition/src/declarations/backend/index.js new file mode 100644 index 000000000..8def37967 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/frontend/frontend.did b/rust/face-recognition/src/declarations/frontend/frontend.did new file mode 100644 index 000000000..51bb1a235 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/frontend/frontend.did.d.ts b/rust/face-recognition/src/declarations/frontend/frontend.did.d.ts new file mode 100644 index 000000000..ce964689f --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/frontend/frontend.did.js b/rust/face-recognition/src/declarations/frontend/frontend.did.js new file mode 100644 index 000000000..b68ea4a42 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/frontend/index.d.ts b/rust/face-recognition/src/declarations/frontend/index.d.ts new file mode 100644 index 000000000..b55074358 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/declarations/frontend/index.js b/rust/face-recognition/src/declarations/frontend/index.js new file mode 100644 index 000000000..c5e4ab186 --- /dev/null +++ b/rust/face-recognition/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/face-recognition/src/frontend/assets/.ic-assets.json5 b/rust/face-recognition/src/frontend/assets/.ic-assets.json5 new file mode 100644 index 000000000..577df191a --- /dev/null +++ b/rust/face-recognition/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=self, 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/face-recognition/src/frontend/assets/default.png b/rust/face-recognition/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/face-recognition/src/frontend/assets/favicon.ico b/rust/face-recognition/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/face-recognition/src/frontend/assets/loader.svg b/rust/face-recognition/src/frontend/assets/loader.svg new file mode 100644 index 000000000..2d448f5d0 --- /dev/null +++ b/rust/face-recognition/src/frontend/assets/loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rust/face-recognition/src/frontend/assets/logo_transparent.png b/rust/face-recognition/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/face-recognition/src/frontend/assets/main.css b/rust/face-recognition/src/frontend/assets/main.css new file mode 100644 index 000000000..8fe6bf178 --- /dev/null +++ b/rust/face-recognition/src/frontend/assets/main.css @@ -0,0 +1,120 @@ +body { + font-family: monospace; + width: 100%; +} + +h1 { + font-size: larger; +} + +form { + display: flex; + justify-content: center; + max-width: 80vw; + margin: auto; +} + +div { + display: flex; + max-width: 80vw; + flex-flow: column; + align-items: baseline; +} + +#camera { + position: relative; + margin-top: 10px; + height: 250px; + cursor: pointer; +} + +#camera>video, +#camera>canvas, +#camera>img { + position: absolute; + top: 0px; + left: 0px; + border: 1px solid #555; + max-width: 350px; + max-height: 350px; + width: auto; + height: 250px; +} + + +.invisible { + visibility: hidden; +} + +@keyframes astrodance { + 0% { + transform: translate(-50%, -50%) rotate(-20deg) + } + + 50% { + transform: translate(-50%, -50%) rotate(10deg) + } + + to { + transform: translate(-50%, -50%) rotate(-20deg) + } +} + +#loader { + width: 32px; + margin-top: -64px; + margin-left: 32px; + display: block; + -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; +} + +#toolbar { + position: relative; + margin-top: 30px; +} + +#buttons { + position: absolute; + top: 0px; + left: 0px; + display: flex; + flex-direction: row; + gap: 10px; + justify-content: center; +} + +#buttons button, +#buttons label { + padding: 5px 10px; + border-radius: 4px; + border: 1px solid #555; + background-color: #eee; + font-size: larger; + cursor: pointer; +} + +#buttons button:hover, +#buttons label:hover { + background-color: #fff; +} + +#message { + max-width: 200px; + font-size: 120%; +} + +input.file { + display: none; +} + +.container { + margin: 0 auto; + width: 350px; +} \ No newline at end of file diff --git a/rust/face-recognition/src/frontend/src/.ic-assets.json5 b/rust/face-recognition/src/frontend/src/.ic-assets.json5 new file mode 100644 index 000000000..577df191a --- /dev/null +++ b/rust/face-recognition/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=self, 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/face-recognition/src/frontend/src/index.html b/rust/face-recognition/src/frontend/src/index.html new file mode 100644 index 000000000..6dae799a3 --- /dev/null +++ b/rust/face-recognition/src/frontend/src/index.html @@ -0,0 +1,41 @@ + + + + + + + ICP face recognition + + + + + + +
+

ICP face recognition

+
+ + +
+ +
+ +
+ +
+ +
+
+
+ + + \ No newline at end of file diff --git a/rust/face-recognition/src/frontend/src/index.js b/rust/face-recognition/src/frontend/src/index.js new file mode 100644 index 000000000..f943f6e54 --- /dev/null +++ b/rust/face-recognition/src/frontend/src/index.js @@ -0,0 +1,266 @@ +import { backend } from "../../declarations/backend"; + +window.onload = async () => { + elem("recognize").onclick = recognize; + elem("store").onclick = store; + elem("file").onchange = load_local_image; + elem("canvas").onclick = restart; + elem("video").oncanplay = () => { + show("video"); + hide("image"); + hide("canvas"); + } + + navigator.mediaDevices + .getUserMedia({ video: true, audio: false }) + .then((stream) => { + const video = elem("video"); + video.srcObject = stream; + video.play(); + show("buttons"); + }) + .catch((err) => { + show("image"); + hide("buttons"); + hide("video"); + hide("canvas"); + console.error(`An error occurred: ${err}`); + message("Couldn't start camera, but you can upload photos.") + }); +} + +// Returns a DOM element that is currently visible and contains an image. +function select_visible_element() { + const video = elem("video"); + const image = elem("image"); + const canvas = elem("canvas"); + if (!video.className.includes("invisible")) { + return [video, video.videoWidth, video.videoHeight]; + } else if (!image.className.includes("invisible")) { + return [image, image.width, image.height]; + } else { + return [canvas, canvas.width, canvas.height]; + } +} + +// Captures the image from the camera stream or from the image element or from +// the canvas element depending on which one of them is visible. +// +// It also scales the image down to 320x240px such that it can be submitted to +// the backend for face detection. +async function capture_image() { + let [image, width, height] = select_visible_element(); + + const canvas = elem("canvas"); + canvas.width = width + canvas.height = height; + const context = canvas.getContext("2d"); + context.drawImage(image, 0, 0, width, height); + + const resized = document.createElement("canvas"); + resized.width = 320; + resized.height = 240; + let scale = Math.min(resized.width / canvas.width, resized.height / canvas.height); + width = canvas.width * scale; + height = canvas.height * scale; + let x = resized.width / 2 - width / 2; + let y = resized.height / 2 - height / 2; + const ctx = resized.getContext("2d"); + if (ctx) { + ctx.drawImage(canvas, x, y, width, height); + } + let bytes = await serialize(resized); + + if (video.srcObject) { + video.srcObject.getTracks().forEach((track) => track.stop()); + } + + hide("video"); + hide("image"); + show("canvas") + return [bytes, { scale, x, y }]; +} + +// Renders the bounding box around the face and also returns a small image of +// the face that can be submitted to the backend for recognition. +async function render(scaling, box) { + box.left = Math.round((box.left * 320 - scaling.x) / scaling.scale); + box.right = Math.round((box.right * 320 - scaling.x) / scaling.scale); + box.top = Math.round((box.top * 240 - scaling.y) / scaling.scale); + box.bottom = Math.round((box.bottom * 240 - scaling.y) / scaling.scale); + + const canvas = elem("canvas"); + + const small = document.createElement("canvas"); + small.width = 160; + small.height = 160; + const ctx2 = small.getContext("2d"); + if (ctx2) { + ctx2.drawImage(canvas, box.left, box.top, box.right - box.left, box.bottom - box.top, 0, 0, 140, 140); + } + let bytes = await serialize(small); + + const ctx = canvas.getContext("2d"); + if (ctx) { + ctx.strokeStyle = "#0f3"; + ctx.lineWidth = 5; + ctx.beginPath(); + ctx.rect(box.left, box.top, box.right - box.left, box.bottom - box.top); + ctx.stroke(); + } + + return bytes; +} + +// This function performs the following steps: +// 1. Capture the image from the camera stream (or from the local file). +// 2. Call the backend to detect the bounding box of the face in the image. +// 3. Call the backend to recognize the face. +async function recognize(event) { + event.preventDefault(); + hide("buttons"); + show("loader"); + message("Detecting face.."); + try { + const [blob, scaling] = await capture_image(); + let result; + result = await backend.detect(new Uint8Array(blob)); + if (!result.Ok) { + throw result.Err.message; + } + let face = await render(scaling, result.Ok); + message("Face detected. Recognizing.."); + result = await backend.recognize(new Uint8Array(face)); + if (!result.Ok) { + throw result.Err.message; + } + let label = sanitize(result.Ok.label); + let score = Math.round(result.Ok.score * 100) / 100; + message(`${label}, difference=${score}`); + } catch (err) { + console.error(`An error occurred: ${err}`); + message(err.toString()); + } + hide("loader"); + return false; +} + +// This function performs the following steps: +// 1. Capture the image from the camera stream (or from the local file). +// 2. Call the backend to detect the bounding box of the face in the image. +// 3. Ask the user for their name. +// 4. Call the backend to store the image and the name of the user. +async function store(event) { + event.preventDefault(); + hide("buttons"); + show("loader"); + message("Detecting face.."); + try { + const [blob, scaling] = await capture_image(); + let result; + result = await backend.detect(new Uint8Array(blob)); + if (!result.Ok) { + throw result.Err.message; + } + let face = await render(scaling, result.Ok); + message("Face detected. Adding.."); + let label = prompt("Enter name of the person"); + if (!label) { + throw "cannot add without a name"; + } + label = sanitize(label); + message(`Face detected. Adding ${label}..`); + result = await backend.add(label, new Uint8Array(face)); + if (!result.Ok) { + throw result.Err.message; + } + message(`Successfully added ${label}.`); + } catch (err) { + console.error(`An error occurred: ${err}`); + message("Failed to add the face: " + err.toString()); + } + + hide("loader"); + return false; +} + +// Invoked when a file is selected in the file input element. +// Loads the given file as an image to show to the user. +async function load_local_image(event) { + message(""); + let image = elem("image"); + try { + const file = event.target.files[0]; + if (!file) { + return false; + } + const url = await toDataURL(file); + image.src = url; + } catch (err) { + message("Failed to select photo: " + err.toString()); + } + hide("video"); + hide("canvas"); + show("image"); + show("buttons"); + 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); + } + }); +} + +// Restarts the face recognition / addition user flow. +async function restart(event) { + message(""); + if (video.srcObject) { + event.preventDefault(); + } + navigator.mediaDevices + .getUserMedia({ video: true, audio: false }) + .then((stream) => { + const video = elem("video"); + video.srcObject = stream; + video.play(); + show("buttons"); + }); +} + +// Returns a DOM element by its id. +function elem(id) { + return document.getElementById(id); +} + +// Makes the given DOM element visible. +function show(id) { + elem(id).className = ""; +} + +// Makes the given DOM element invisible. +function hide(id) { + elem(id).className = "invisible"; +} + +// Sets the message element's text to the given text. +function message(m) { + elem("message").innerText = m; +} + +// Returns an PNG image from the canvas. +function serialize(canvas) { + return new Promise((resolve) => canvas.toBlob((blob) => blob.arrayBuffer().then(resolve), "image/png", 0.9)); +} + +// Sanitizes the name string by filtering out characters that are not letters, +// numbers, spaces, and dashes. +function sanitize(name) { + return name.match(/[\p{L}\p{N}\s_-]/gu).join(''); +} diff --git a/rust/face-recognition/upload-models-to-canister.sh b/rust/face-recognition/upload-models-to-canister.sh new file mode 100755 index 000000000..0855a61d7 --- /dev/null +++ b/rust/face-recognition/upload-models-to-canister.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +dfx canister call backend clear_face_detection_model_bytes +dfx canister call backend clear_face_recognition_model_bytes +upload_byte_file backend append_face_detection_model_bytes . version-RFB-320.onnx +upload_byte_file backend append_face_recognition_model_bytes . face-recognition.onnx +dfx canister call backend setup_models diff --git a/rust/face-recognition/webpack.config.js b/rust/face-recognition/webpack.config.js new file mode 100644 index 000000000..4792c054a --- /dev/null +++ b/rust/face-recognition/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, + }, +}; From 996d6b8fb4b2f6a461ce134651abd70ce79eb1ee Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Thu, 11 Jul 2024 12:46:08 +0200 Subject: [PATCH 2/9] More refactoring --- rust/face-recognition/dfx.json | 3 +- .../src/frontend/assets/main.css | 42 ++++++++++++------- .../src/frontend/src/index.html | 11 +++-- .../src/frontend/src/index.js | 4 ++ 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/rust/face-recognition/dfx.json b/rust/face-recognition/dfx.json index e5ee40ef0..f65ea3f85 100644 --- a/rust/face-recognition/dfx.json +++ b/rust/face-recognition/dfx.json @@ -26,6 +26,7 @@ "type": "assets" } }, + "dfx": "0.22.0-beta.0", "defaults": { "build": { "args": "", @@ -34,4 +35,4 @@ }, "output_env_file": ".env", "version": 1 -} \ No newline at end of file +} diff --git a/rust/face-recognition/src/frontend/assets/main.css b/rust/face-recognition/src/frontend/assets/main.css index 8fe6bf178..2294b33f6 100644 --- a/rust/face-recognition/src/frontend/assets/main.css +++ b/rust/face-recognition/src/frontend/assets/main.css @@ -1,6 +1,9 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); + body { font-family: monospace; width: 100%; + color: #2563eb; } h1 { @@ -24,7 +27,7 @@ div { #camera { position: relative; margin-top: 10px; - height: 250px; + height: 320px; cursor: pointer; } @@ -34,11 +37,11 @@ div { position: absolute; top: 0px; left: 0px; - border: 1px solid #555; - max-width: 350px; - max-height: 350px; + border: 1px solid #2563eb; + max-width: 450px; width: auto; - height: 250px; + height: 320px; + border-radius: 0.6rem; } @@ -86,27 +89,34 @@ div { left: 0px; display: flex; flex-direction: row; - gap: 10px; + gap: 1rem; justify-content: center; } -#buttons button, +button, #buttons label { - padding: 5px 10px; - border-radius: 4px; - border: 1px solid #555; - background-color: #eee; - font-size: larger; + text-wrap: nowrap; + display: inline; + padding: 0.75rem 1rem; + border: none; + border-radius: 0.5rem; + background-color: #2563eb; + color: #fff; cursor: pointer; } -#buttons button:hover, +button:hover, #buttons label:hover { - background-color: #fff; + background-color: #3583fb; +} + +button i { + margin-right: 0.5rem; + font-size: 1rem; } #message { - max-width: 200px; + max-width: 300px; font-size: 120%; } @@ -116,5 +126,5 @@ input.file { .container { margin: 0 auto; - width: 350px; + width: 450px; } \ No newline at end of file diff --git a/rust/face-recognition/src/frontend/src/index.html b/rust/face-recognition/src/frontend/src/index.html index 6dae799a3..f51dd753f 100644 --- a/rust/face-recognition/src/frontend/src/index.html +++ b/rust/face-recognition/src/frontend/src/index.html @@ -4,15 +4,16 @@ - ICP face recognition + On-chain ICP face recognition +
-

ICP face recognition

+

On-chain ICP face recognition