diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a25e2e7..df64d9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,70 +1,70 @@ -name: Build -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - build-server: - name: Server - runs-on: ubuntu-latest - container: golang:alpine - steps: - - uses: actions/checkout@v4 - - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-go@v5 - - run: task server:build - - uses: actions/upload-artifact@v4 - with: - path: server/build/botw-iss - name: server - retention-days: 3 - - build-manual: - name: Manual - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: cargo-bins/cargo-binstall@main - - run: cargo-binstall --no-confirm mdbook - - run: task manual:build - - uses: actions/upload-artifact@v4 - with: - path: manual/book - name: manual - retention-days: 3 - - build-legacy: - name: Legacy App - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - uses: actions/setup-node@v4 - with: - node-version: 18.x - - run: task leg:ci - - run: task leg:build - - uses: actions/upload-artifact@v4 - with: - path: legacy/dist - name: legacy - retention-days: 3 +# name: Build +# on: +# push: +# branches: +# - main +# pull_request: +# branches: +# - main +# +# jobs: +# build-server: +# name: Server +# runs-on: ubuntu-latest +# container: golang:alpine +# steps: +# - uses: actions/checkout@v4 +# - uses: arduino/setup-task@v2 +# with: +# version: 3.x +# repo-token: ${{ secrets.GITHUB_TOKEN }} +# - uses: actions/setup-go@v5 +# - run: task server:build +# - uses: actions/upload-artifact@v4 +# with: +# path: server/build/botw-iss +# name: server +# retention-days: 3 +# +# build-manual: +# name: Manual +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: arduino/setup-task@v2 +# with: +# version: 3.x +# repo-token: ${{ secrets.GITHUB_TOKEN }} +# - uses: cargo-bins/cargo-binstall@main +# - run: cargo-binstall --no-confirm mdbook +# - run: task manual:build +# - uses: actions/upload-artifact@v4 +# with: +# path: manual/book +# name: manual +# retention-days: 3 + # build-legacy: + # name: Legacy App + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: arduino/setup-task@v2 + # with: + # version: 3.x + # repo-token: ${{ secrets.GITHUB_TOKEN }} + # - uses: actions/setup-python@v5 + # with: + # python-version: '3.11' + # - uses: actions/setup-node@v4 + # with: + # node-version: 18.x + # - run: task leg:ci + # - run: task leg:build + # - uses: actions/upload-artifact@v4 + # with: + # path: legacy/dist + # name: legacy + # retention-days: 3 + # diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a05d4e9..dbd8cfc 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,40 +1,22 @@ -name: Check -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - check-server: - name: Server - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-go@v5 - - run: task server:check - - check-legacy: - name: Legacy App - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: arduino/setup-task@v2 - with: - version: 3.x - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - uses: actions/setup-node@v4 - with: - node-version: 18.x - - run: task leg:ci - - run: task leg:test - - run: task leg:check +# name: Check +# on: +# push: +# branches: +# - main +# pull_request: +# branches: +# - main +# +# jobs: +# check-server: +# name: Server +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: arduino/setup-task@v2 +# with: +# version: 3.x +# repo-token: ${{ secrets.GITHUB_TOKEN }} +# - uses: actions/setup-go@v5 +# - run: task server:check +# diff --git a/.gitignore b/.gitignore index 5d89c61..9edab59 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,8 @@ # Cargo /target + +# NPM +/node_modules + +/packages/workex diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..be17ce9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +*.yaml +*.yml +*.gen.ts diff --git a/Cargo.lock b/Cargo.lock index 126b08e..f27fa22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "actor-sys" +version = "0.0.0" + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +21,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "allocator-api2" version = "0.2.20" @@ -83,9 +99,32 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "arbitrary" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" @@ -93,34 +132,136 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +dependencies = [ + "arrayvec", +] + [[package]] name = "beef" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[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 = "blueflame" +version = "0.0.0" +dependencies = [ + "derive_more", + "enumset", + "rand_xoshiro", + "sha2", + "thiserror 2.0.9", + "uking-relocate-lib", +] + +[[package]] +name = "blueflame-macros" +version = "0.0.0" + [[package]] name = "botw-ist-command" version = "0.0.0" dependencies = [ - "logos", + "logos 0.14.2", "phf", - "teleparse", + "teleparse 0.0.4", "thiserror 1.0.64", ] +[[package]] +name = "built" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "cassowary" version = "0.3.0" @@ -142,9 +283,21 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -173,9 +326,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -183,9 +336,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -202,14 +355,29 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "codize" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "9fc5c2a8623ba8c093aeadf57a112769a87bd364233c0a466643210b78208fbd" +dependencies = [ + "derivative", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" @@ -246,13 +414,56 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.6.0", "crossterm_winapi", "mio", "parking_lot", @@ -271,6 +482,22 @@ dependencies = [ "winapi", ] +[[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 = "ctrlc" version = "3.4.5" @@ -302,7 +529,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] @@ -313,7 +540,32 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.89", + "syn 2.0.92", +] + +[[package]] +name = "deku" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9711031e209dc1306d66985363b4397d4c7b911597580340b93c9729b55f6eb" +dependencies = [ + "bitvec", + "deku_derive", + "no_std_io2", + "rustversion", +] + +[[package]] +name = "deku_derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cb0719583cbe4e81fb40434ace2f0d22ccc3e39a74bb3796c22b451b4f139d" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.92", ] [[package]] @@ -356,7 +608,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", "unicode-xid", ] @@ -366,12 +618,43 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[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 = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "enumset" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.92", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -388,6 +671,40 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -400,6 +717,59 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[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 = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.15.0" @@ -452,6 +822,57 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", +] + +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "indexmap" version = "2.6.0" @@ -479,7 +900,18 @@ dependencies = [ "pretty_assertions", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", ] [[package]] @@ -489,18 +921,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] -name = "ist-parser" -version = "0.0.0" -dependencies = [ - "logos", - "teleparse", -] - -[[package]] -name = "ist-runtime" -version = "0.0.0" +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ - "ist-parser", + "either", ] [[package]] @@ -518,12 +944,28 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -533,12 +975,51 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +[[package]] +name = "libfuzzer-sys" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libwebp-sys" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cd30df7c7165ce74a456e4ca9732c603e8dc5e60784558c1c6dc047f876733" +dependencies = [ + "cc", + "glob", +] + +[[package]] +name = "libwebp-sys2" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3196c90eb6895d0b6b9520bcc942afa0daf836f928bee77035cc78d4fa1ca163" +dependencies = [ + "cc", + "cfg-if", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -567,7 +1048,16 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b" dependencies = [ - "logos-derive", + "logos-derive 0.14.2", +] + +[[package]] +name = "logos" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6f536c1af4c7cc81edf73da1f8029896e7e1e16a219ef09b184e76a296f3db" +dependencies = [ + "logos-derive 0.15.0", ] [[package]] @@ -582,7 +1072,23 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn 2.0.89", + "syn 2.0.92", +] + +[[package]] +name = "logos-codegen" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189bbfd0b61330abea797e5e9276408f2edbe4f822d7ad08685d67419aafb34e" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "rustc_version", + "syn 2.0.92", ] [[package]] @@ -591,7 +1097,25 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec" dependencies = [ - "logos-codegen", + "logos-codegen 0.14.2", +] + +[[package]] +name = "logos-derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebfe8e1a19049ddbfccbd14ac834b215e11b85b90bab0c2dba7c7b92fb5d5cba" +dependencies = [ + "logos-codegen 0.15.0", +] + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", ] [[package]] @@ -603,12 +1127,38 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[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.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.0.2" @@ -622,18 +1172,49 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", ] +[[package]] +name = "no_std_io2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3564ce7035b1e4778d8cb6cacebb5d766b5e8fe5a75b9e441e33fb61a872c6" +dependencies = [ + "memchr", +] + +[[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 = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "num" version = "0.4.3" @@ -667,6 +1248,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -775,7 +1367,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] @@ -787,12 +1379,40 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "portable-atomic" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -821,29 +1441,93 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn 2.0.92", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core", + "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_core" -version = "0.6.4" +name = "rand_xoshiro" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] [[package]] name = "ratatui" @@ -851,13 +1535,13 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cassowary", "compact_str", "crossterm", "indoc", "instability", - "itertools", + "itertools 0.13.0", "lru", "paste", "strum", @@ -866,20 +1550,90 @@ dependencies = [ "unicode-width 0.2.0", ] +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror 1.0.64", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[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.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -904,13 +1658,28 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ - "bitflags", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -935,31 +1704,37 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + [[package]] name = "serde" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -967,6 +1742,48 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_variant" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0068df419f9d9b6488fdded3f1c818522cdea328e02ce9d9f147380265a432" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml_ng" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[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 = "shlex" version = "1.3.0" @@ -1004,12 +1821,18 @@ dependencies = [ ] [[package]] -name = "sim" -version = "0.0.0" +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" dependencies = [ - "ist-parser", - "ist-runtime", - "wasm-bindgen", + "quote", ] [[package]] @@ -1018,6 +1841,69 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "skybook-acorn" +version = "0.0.0" +dependencies = [ + "enumset", + "heck", + "serde", + "serde_variant", + "serde_yaml_ng", +] + +[[package]] +name = "skybook-item-animated-encode" +version = "0.0.0" +dependencies = [ + "anyhow", + "clap", + "image 0.25.5", + "serde", + "serde_yaml_ng", + "webp-animation", +] + +[[package]] +name = "skybook-item-sprites-generator" +version = "0.0.0" +dependencies = [ + "anyhow", + "codize", + "image 0.25.5", + "serde", + "serde_json", + "thiserror 2.0.9", + "webp", +] + +[[package]] +name = "skybook-parser" +version = "0.0.0" +dependencies = [ + "derive_more", + "teleparse 0.0.5", + "thiserror 2.0.9", +] + +[[package]] +name = "skybook-runtime" +version = "0.0.0" +dependencies = [ + "blueflame", + "skybook-parser", +] + +[[package]] +name = "skybook-runtime-wasm" +version = "0.0.0" +dependencies = [ + "skybook-parser", + "skybook-runtime", + "teleparse 0.0.5", + "wasm-bindgen", +] + [[package]] name = "skybook-trace-view" version = "0.0.0" @@ -1031,7 +1917,7 @@ dependencies = [ "ratatui", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 2.0.9", ] [[package]] @@ -1071,7 +1957,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] @@ -1087,15 +1973,40 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.89" +version = "2.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "teleparse" version = "0.0.4" @@ -1104,13 +2015,28 @@ checksum = "80436d09591939259a48971e0958fa1f448ccfc52cd866aa6e3a2ac22f453a7a" dependencies = [ "deref-derive", "derivative", - "itertools", - "logos", + "itertools 0.13.0", + "logos 0.14.2", "num", - "teleparse-macros", + "teleparse-macros 0.0.4", "thiserror 1.0.64", ] +[[package]] +name = "teleparse" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f9b8e0b35f32a2a8764f1ec9ca73cf7e5f891b1fd202732d7aef44cd754046" +dependencies = [ + "deref-derive", + "derivative", + "itertools 0.13.0", + "logos 0.15.0", + "num", + "teleparse-macros 0.0.5", + "thiserror 2.0.9", +] + [[package]] name = "teleparse-macros" version = "0.0.4" @@ -1121,7 +2047,20 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.89", + "syn 2.0.92", +] + +[[package]] +name = "teleparse-macros" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3618b9de151b5026c7de82b32a4f4445a97fe6c97959d1f274896d7c4e18aa" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 2.0.92", ] [[package]] @@ -1135,11 +2074,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.9", ] [[package]] @@ -1150,18 +2089,41 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] @@ -1169,6 +2131,9 @@ name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -1177,10 +2142,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uking-relocate-lib" +version = "0.0.0" +source = "git+https://github.com/Pistonight/symbotw?rev=57e51a922e4e3c83d13d97d6e183a32f0533113e#57e51a922e4e3c83d13d97d6e183a32f0533113e" +dependencies = [ + "deku", + "flate2", + "serde", + "thiserror 2.0.9", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -1199,7 +2183,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools", + "itertools 0.13.0", "unicode-segmentation", "unicode-width 0.1.14", ] @@ -1222,12 +2206,47 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1236,35 +2255,36 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", + "serde", + "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1272,22 +2292,49 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.92", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "webp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f53152f51fb5af0c08484c33d16cca96175881d1f3dec068c23b31a158c2d99" +dependencies = [ + "image 0.25.5", + "libwebp-sys", +] + +[[package]] +name = "webp-animation" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a656b424e13a9e8b35f2cb7f96ff81c9d796b7ce3b6966cd4f8fd4a15feba4" +dependencies = [ + "image 0.24.9", + "libwebp-sys2", + "log", +] + +[[package]] +name = "weezl" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "winapi" @@ -1411,8 +2458,62 @@ dependencies = [ "memchr", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 4039500..df205d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,15 @@ [workspace] resolver = "2" -members = [ "app/src/sim", - "sim/parser", - "sim/runtime", - "next/botw-ist-command", "research/trace-view", +members = [ + "packages/runtime", + "next/botw-ist-command", + "research/trace-view", + "packages/actor-sys", + "packages/item-assets", + "packages/item-animated", + "packages/parser", + "packages/runtime-wasm", + "packages/acorn", + "packages/blueflame", + "packages/blueflame-macros", ] diff --git a/Taskfile.yml b/Taskfile.yml index f8169e5..242dc6d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,8 +8,12 @@ dotenv: [".env"] includes: app: - taskfile: ./app - dir: ./app + taskfile: ./packages/app + dir: ./packages/app + + monaco-editor: + taskfile: ./packages/monaco-editor-contrib + dir: ./packages/monaco-editor-contrib manual: aliases: [man] @@ -36,7 +40,22 @@ includes: dir: ./research/trace-view tasks: - install: + npm-install: + aliases: [npmi] + desc: Wrapper for npm install to put everything in the right place + cmds: + - task: monaco-editor:clean + - npm install + - task: fix-npm-installs + + fix-npm-installs: + cmds: + - mv node_modules/monaco-editor packages/monaco-editor-contrib/lib + - task: monaco-editor:patch + + + + install-tools: desc: Install tools cmds: - cargo install mdbook live-server cargo-watch wasm-pack diff --git a/app/package-lock.json b/app/package-lock.json deleted file mode 100644 index c251228..0000000 --- a/app/package-lock.json +++ /dev/null @@ -1,3063 +0,0 @@ -{ - "name": "botw-ist", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "botw-ist", - "version": "0.0.0", - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.9.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "eslint": "^9.9.0", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.9", - "globals": "^15.9.0", - "prettier": "^3.3.3", - "typescript": "^5.5.3", - "typescript-eslint": "^8.0.1", - "vite": "^5.4.1" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.6", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", - "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.6" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", - "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", - "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", - "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", - "dev": true, - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "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/@rollup/rollup-android-arm-eabi": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", - "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz", - "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz", - "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz", - "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz", - "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz", - "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz", - "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz", - "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz", - "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz", - "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz", - "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz", - "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz", - "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz", - "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz", - "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz", - "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, - "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/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.10", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz", - "integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", - "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/type-utils": "8.7.0", - "@typescript-eslint/utils": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", - "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", - "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", - "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.7.0", - "@typescript-eslint/utils": "8.7.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", - "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", - "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", - "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", - "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.7.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz", - "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "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/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/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "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/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.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", - "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.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001664", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz", - "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==", - "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/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "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/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "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/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.5.29", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", - "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz", - "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.1", - "@eslint/plugin-kit": "^0.2.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.1.0-rc-fb9a90fa48-20240614", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz", - "integrity": "sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz", - "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==", - "dev": true, - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "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/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/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.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/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "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/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "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/globals": { - "version": "15.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", - "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "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-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-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-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "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/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "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/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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-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/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "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/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "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/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/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "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/rollup": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz", - "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.22.5", - "@rollup/rollup-android-arm64": "4.22.5", - "@rollup/rollup-darwin-arm64": "4.22.5", - "@rollup/rollup-darwin-x64": "4.22.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.22.5", - "@rollup/rollup-linux-arm-musleabihf": "4.22.5", - "@rollup/rollup-linux-arm64-gnu": "4.22.5", - "@rollup/rollup-linux-arm64-musl": "4.22.5", - "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5", - "@rollup/rollup-linux-riscv64-gnu": "4.22.5", - "@rollup/rollup-linux-s390x-gnu": "4.22.5", - "@rollup/rollup-linux-x64-gnu": "4.22.5", - "@rollup/rollup-linux-x64-musl": "4.22.5", - "@rollup/rollup-win32-arm64-msvc": "4.22.5", - "@rollup/rollup-win32-ia32-msvc": "4.22.5", - "@rollup/rollup-win32-x64-msvc": "4.22.5", - "fsevents": "~2.3.2" - } - }, - "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/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "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/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "engines": { - "node": ">=0.10.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-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.7.0.tgz", - "integrity": "sha512-nEHbEYJyHwsuf7c3V3RS7Saq+1+la3i0ieR3qP0yjqWSzVmh8Drp47uOl9LjbPANac4S7EFSqvcYIKXUUwIfIQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.7.0", - "@typescript-eslint/parser": "8.7.0", - "@typescript-eslint/utils": "8.7.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "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.2.0", - "picocolors": "^1.1.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/vite": { - "version": "5.4.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", - "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "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/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/app/package.json b/app/package.json deleted file mode 100644 index 0e21f2e..0000000 --- a/app/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "botw-ist", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.9.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "eslint": "^9.9.0", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.9", - "globals": "^15.9.0", - "prettier": "^3.3.3", - "typescript": "^5.5.3", - "typescript-eslint": "^8.0.1", - "vite": "^5.4.1" - }, - "prettier": { - "tabWidth": 4, - "endOfLine": "auto" - } -} diff --git a/app/public/vite.svg b/app/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/app/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/App.css b/app/src/App.css deleted file mode 100644 index b9d355d..0000000 --- a/app/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/app/src/App.tsx b/app/src/App.tsx deleted file mode 100644 index afe48ac..0000000 --- a/app/src/App.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' - -function App() { - const [count, setCount] = useState(0) - - return ( - <> -
- - Vite logo - - - React logo - -
-

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ) -} - -export default App diff --git a/app/src/assets/react.svg b/app/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/app/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/index.css b/app/src/index.css deleted file mode 100644 index 6119ad9..0000000 --- a/app/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/app/src/main.tsx b/app/src/main.tsx deleted file mode 100644 index 6f4ac9b..0000000 --- a/app/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import App from './App.tsx' -import './index.css' - -createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/app/src/sim/Cargo.toml b/app/src/sim/Cargo.toml deleted file mode 100644 index 8fc2eb0..0000000 --- a/app/src/sim/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sim" -version = "0.0.0" -edition = "2021" -publish = false - -[dependencies] -ist-parser = { path = "../../../sim/parser" } -ist-runtime = { path = "../../../sim/runtime" } -wasm-bindgen = "0.2.93" diff --git a/app/src/vite-env.d.ts b/app/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/app/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/app/vite.config.ts b/app/vite.config.ts deleted file mode 100644 index 5a33944..0000000 --- a/app/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}) diff --git a/app/tsconfig.node.json b/config/tsconfig-tool.json similarity index 75% rename from app/tsconfig.node.json rename to config/tsconfig-tool.json index 0d3d714..4f53603 100644 --- a/app/tsconfig.node.json +++ b/config/tsconfig-tool.json @@ -6,7 +6,7 @@ "skipLibCheck": true, /* Bundler mode */ - "moduleResolution": "bundler", + "moduleResolution": "Bundler", "allowImportingTsExtensions": true, "isolatedModules": true, "moduleDetection": "force", @@ -16,7 +16,7 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + } } diff --git a/config/tsconfig-vite-app.json b/config/tsconfig-vite-app.json new file mode 100644 index 0000000..286c69d --- /dev/null +++ b/config/tsconfig-vite-app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "types": ["vite/client"], + } +} diff --git a/legacy/public/assets/Background.png b/legacy/public/assets/Background.png deleted file mode 100644 index 605800d..0000000 Binary files a/legacy/public/assets/Background.png and /dev/null differ diff --git a/legacy/public/assets/font/DejaVuSansMono.ttf b/legacy/public/assets/font/DejaVuSansMono.ttf deleted file mode 100644 index f578602..0000000 Binary files a/legacy/public/assets/font/DejaVuSansMono.ttf and /dev/null differ diff --git a/legacy/public/assets/img/Armor/AmberEarrings.png b/legacy/public/assets/img/Armor/AmberEarrings.png deleted file mode 100644 index d532ba6..0000000 Binary files a/legacy/public/assets/img/Armor/AmberEarrings.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/AncientCuirass.png b/legacy/public/assets/img/Armor/AncientCuirass.png deleted file mode 100644 index 8c33a27..0000000 Binary files a/legacy/public/assets/img/Armor/AncientCuirass.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/AncientGreaves.png b/legacy/public/assets/img/Armor/AncientGreaves.png deleted file mode 100644 index fc6c167..0000000 Binary files a/legacy/public/assets/img/Armor/AncientGreaves.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/AncientHelm.png b/legacy/public/assets/img/Armor/AncientHelm.png deleted file mode 100644 index 4c77ac8..0000000 Binary files a/legacy/public/assets/img/Armor/AncientHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/BarbarianArmor.png b/legacy/public/assets/img/Armor/BarbarianArmor.png deleted file mode 100644 index 98f5ca0..0000000 Binary files a/legacy/public/assets/img/Armor/BarbarianArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/BarbarianHelm.png b/legacy/public/assets/img/Armor/BarbarianHelm.png deleted file mode 100644 index 1e45592..0000000 Binary files a/legacy/public/assets/img/Armor/BarbarianHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/BarbarianLegWraps.png b/legacy/public/assets/img/Armor/BarbarianLegWraps.png deleted file mode 100644 index 67d6589..0000000 Binary files a/legacy/public/assets/img/Armor/BarbarianLegWraps.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/BokoblinMask.png b/legacy/public/assets/img/Armor/BokoblinMask.png deleted file mode 100644 index a0362df..0000000 Binary files a/legacy/public/assets/img/Armor/BokoblinMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTheHero.png b/legacy/public/assets/img/Armor/CapOfTheHero.png deleted file mode 100644 index 72774a0..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTheHero.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTheSky.png b/legacy/public/assets/img/Armor/CapOfTheSky.png deleted file mode 100644 index a285291..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTheSky.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTheWild.png b/legacy/public/assets/img/Armor/CapOfTheWild.png deleted file mode 100644 index e5b7ddb..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTheWild.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTheWind.png b/legacy/public/assets/img/Armor/CapOfTheWind.png deleted file mode 100644 index 49d7bc6..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTheWind.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTime.png b/legacy/public/assets/img/Armor/CapOfTime.png deleted file mode 100644 index 1c5842a..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTime.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/CapOfTwilight.png b/legacy/public/assets/img/Armor/CapOfTwilight.png deleted file mode 100644 index a43685d..0000000 Binary files a/legacy/public/assets/img/Armor/CapOfTwilight.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ChampionsTunic.png b/legacy/public/assets/img/Armor/ChampionsTunic.png deleted file mode 100644 index bafa5ea..0000000 Binary files a/legacy/public/assets/img/Armor/ChampionsTunic.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ClimbersBandanna.png b/legacy/public/assets/img/Armor/ClimbersBandanna.png deleted file mode 100644 index 5067253..0000000 Binary files a/legacy/public/assets/img/Armor/ClimbersBandanna.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ClimbingBoots.png b/legacy/public/assets/img/Armor/ClimbingBoots.png deleted file mode 100644 index 40665cd..0000000 Binary files a/legacy/public/assets/img/Armor/ClimbingBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ClimbingGear.png b/legacy/public/assets/img/Armor/ClimbingGear.png deleted file mode 100644 index 6403188..0000000 Binary files a/legacy/public/assets/img/Armor/ClimbingGear.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DarkHood.png b/legacy/public/assets/img/Armor/DarkHood.png deleted file mode 100644 index 19a7117..0000000 Binary files a/legacy/public/assets/img/Armor/DarkHood.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DarkTrousers.png b/legacy/public/assets/img/Armor/DarkTrousers.png deleted file mode 100644 index 290ff64..0000000 Binary files a/legacy/public/assets/img/Armor/DarkTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DarkTunic.png b/legacy/public/assets/img/Armor/DarkTunic.png deleted file mode 100644 index f2ea179..0000000 Binary files a/legacy/public/assets/img/Armor/DarkTunic.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DesertVoeHeadband.png b/legacy/public/assets/img/Armor/DesertVoeHeadband.png deleted file mode 100644 index dd47c82..0000000 Binary files a/legacy/public/assets/img/Armor/DesertVoeHeadband.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DesertVoeSpaulder.png b/legacy/public/assets/img/Armor/DesertVoeSpaulder.png deleted file mode 100644 index 7e14a3e..0000000 Binary files a/legacy/public/assets/img/Armor/DesertVoeSpaulder.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DesertVoeTrousers.png b/legacy/public/assets/img/Armor/DesertVoeTrousers.png deleted file mode 100644 index 8d8cadc..0000000 Binary files a/legacy/public/assets/img/Armor/DesertVoeTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/DiamondCirclet.png b/legacy/public/assets/img/Armor/DiamondCirclet.png deleted file mode 100644 index d923fca..0000000 Binary files a/legacy/public/assets/img/Armor/DiamondCirclet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FierceDeityArmor.png b/legacy/public/assets/img/Armor/FierceDeityArmor.png deleted file mode 100644 index 3463bcf..0000000 Binary files a/legacy/public/assets/img/Armor/FierceDeityArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FierceDeityBoots.png b/legacy/public/assets/img/Armor/FierceDeityBoots.png deleted file mode 100644 index 6e74133..0000000 Binary files a/legacy/public/assets/img/Armor/FierceDeityBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FierceDeityMask.png b/legacy/public/assets/img/Armor/FierceDeityMask.png deleted file mode 100644 index 2a1c322..0000000 Binary files a/legacy/public/assets/img/Armor/FierceDeityMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FlamebreakerArmor.png b/legacy/public/assets/img/Armor/FlamebreakerArmor.png deleted file mode 100644 index 9c16728..0000000 Binary files a/legacy/public/assets/img/Armor/FlamebreakerArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FlamebreakerBoots.png b/legacy/public/assets/img/Armor/FlamebreakerBoots.png deleted file mode 100644 index c3ae20d..0000000 Binary files a/legacy/public/assets/img/Armor/FlamebreakerBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/FlamebreakerHelm.png b/legacy/public/assets/img/Armor/FlamebreakerHelm.png deleted file mode 100644 index 5d76e9a..0000000 Binary files a/legacy/public/assets/img/Armor/FlamebreakerHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/GerudoSirwal.png b/legacy/public/assets/img/Armor/GerudoSirwal.png deleted file mode 100644 index cef69c4..0000000 Binary files a/legacy/public/assets/img/Armor/GerudoSirwal.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/GerudoTop.png b/legacy/public/assets/img/Armor/GerudoTop.png deleted file mode 100644 index 568f03f..0000000 Binary files a/legacy/public/assets/img/Armor/GerudoTop.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/GerudoVeil.png b/legacy/public/assets/img/Armor/GerudoVeil.png deleted file mode 100644 index b2ce8cc..0000000 Binary files a/legacy/public/assets/img/Armor/GerudoVeil.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/HylianHood.png b/legacy/public/assets/img/Armor/HylianHood.png deleted file mode 100644 index 8752ee6..0000000 Binary files a/legacy/public/assets/img/Armor/HylianHood.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/HylianTrousers.png b/legacy/public/assets/img/Armor/HylianTrousers.png deleted file mode 100644 index 6279626..0000000 Binary files a/legacy/public/assets/img/Armor/HylianTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/HylianTunic.png b/legacy/public/assets/img/Armor/HylianTunic.png deleted file mode 100644 index 1967936..0000000 Binary files a/legacy/public/assets/img/Armor/HylianTunic.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/IslandLobsterShirt.png b/legacy/public/assets/img/Armor/IslandLobsterShirt.png deleted file mode 100644 index c1adeb8..0000000 Binary files a/legacy/public/assets/img/Armor/IslandLobsterShirt.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/KorokMask.png b/legacy/public/assets/img/Armor/KorokMask.png deleted file mode 100644 index 1cc62f4..0000000 Binary files a/legacy/public/assets/img/Armor/KorokMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/LizalfosMask.png b/legacy/public/assets/img/Armor/LizalfosMask.png deleted file mode 100644 index 41cb31c..0000000 Binary files a/legacy/public/assets/img/Armor/LizalfosMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/LynelMask.png b/legacy/public/assets/img/Armor/LynelMask.png deleted file mode 100644 index 1e5dce7..0000000 Binary files a/legacy/public/assets/img/Armor/LynelMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/MajorasMask.png b/legacy/public/assets/img/Armor/MajorasMask.png deleted file mode 100644 index 20dc8aa..0000000 Binary files a/legacy/public/assets/img/Armor/MajorasMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/MidnasHelmet.png b/legacy/public/assets/img/Armor/MidnasHelmet.png deleted file mode 100644 index 5590c49..0000000 Binary files a/legacy/public/assets/img/Armor/MidnasHelmet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/MoblinMask.png b/legacy/public/assets/img/Armor/MoblinMask.png deleted file mode 100644 index 9b71698..0000000 Binary files a/legacy/public/assets/img/Armor/MoblinMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/NintendoSwitchShirt.png b/legacy/public/assets/img/Armor/NintendoSwitchShirt.png deleted file mode 100644 index 31db1da..0000000 Binary files a/legacy/public/assets/img/Armor/NintendoSwitchShirt.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/OldShirt.png b/legacy/public/assets/img/Armor/OldShirt.png deleted file mode 100644 index 57ac0a2..0000000 Binary files a/legacy/public/assets/img/Armor/OldShirt.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/OpalEarrings.png b/legacy/public/assets/img/Armor/OpalEarrings.png deleted file mode 100644 index 3243d6d..0000000 Binary files a/legacy/public/assets/img/Armor/OpalEarrings.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomArmor.png b/legacy/public/assets/img/Armor/PhantomArmor.png deleted file mode 100644 index 68866f4..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomGanonArmor.png b/legacy/public/assets/img/Armor/PhantomGanonArmor.png deleted file mode 100644 index 87ca398..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomGanonArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomGanonGreaves.png b/legacy/public/assets/img/Armor/PhantomGanonGreaves.png deleted file mode 100644 index b63a8e2..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomGanonGreaves.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomGanonSkull.png b/legacy/public/assets/img/Armor/PhantomGanonSkull.png deleted file mode 100644 index 974fbad..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomGanonSkull.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomGreaves.png b/legacy/public/assets/img/Armor/PhantomGreaves.png deleted file mode 100644 index e9fe0cd..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomGreaves.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/PhantomHelmet.png b/legacy/public/assets/img/Armor/PhantomHelmet.png deleted file mode 100644 index 7e446ad..0000000 Binary files a/legacy/public/assets/img/Armor/PhantomHelmet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RadiantMask.png b/legacy/public/assets/img/Armor/RadiantMask.png deleted file mode 100644 index a06f2fc..0000000 Binary files a/legacy/public/assets/img/Armor/RadiantMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RadiantShirt.png b/legacy/public/assets/img/Armor/RadiantShirt.png deleted file mode 100644 index 703a8bb..0000000 Binary files a/legacy/public/assets/img/Armor/RadiantShirt.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RadiantTights.png b/legacy/public/assets/img/Armor/RadiantTights.png deleted file mode 100644 index 0e3d50b..0000000 Binary files a/legacy/public/assets/img/Armor/RadiantTights.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RaviosHood.png b/legacy/public/assets/img/Armor/RaviosHood.png deleted file mode 100644 index 6288cd6..0000000 Binary files a/legacy/public/assets/img/Armor/RaviosHood.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RoyalGuardBoots.png b/legacy/public/assets/img/Armor/RoyalGuardBoots.png deleted file mode 100644 index 3ce627c..0000000 Binary files a/legacy/public/assets/img/Armor/RoyalGuardBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RoyalGuardCap.png b/legacy/public/assets/img/Armor/RoyalGuardCap.png deleted file mode 100644 index 42c90d8..0000000 Binary files a/legacy/public/assets/img/Armor/RoyalGuardCap.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RoyalGuardUniform.png b/legacy/public/assets/img/Armor/RoyalGuardUniform.png deleted file mode 100644 index 927faf2..0000000 Binary files a/legacy/public/assets/img/Armor/RoyalGuardUniform.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RubberArmor.png b/legacy/public/assets/img/Armor/RubberArmor.png deleted file mode 100644 index 84a2408..0000000 Binary files a/legacy/public/assets/img/Armor/RubberArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RubberHelm.png b/legacy/public/assets/img/Armor/RubberHelm.png deleted file mode 100644 index 660fa88..0000000 Binary files a/legacy/public/assets/img/Armor/RubberHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RubberTights.png b/legacy/public/assets/img/Armor/RubberTights.png deleted file mode 100644 index abb7468..0000000 Binary files a/legacy/public/assets/img/Armor/RubberTights.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/RubyCirclet.png b/legacy/public/assets/img/Armor/RubyCirclet.png deleted file mode 100644 index 89b8d82..0000000 Binary files a/legacy/public/assets/img/Armor/RubyCirclet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SalvagerHeadwear.png b/legacy/public/assets/img/Armor/SalvagerHeadwear.png deleted file mode 100644 index 159e316..0000000 Binary files a/legacy/public/assets/img/Armor/SalvagerHeadwear.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SalvagerTrousers.png b/legacy/public/assets/img/Armor/SalvagerTrousers.png deleted file mode 100644 index 39df17d..0000000 Binary files a/legacy/public/assets/img/Armor/SalvagerTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SalvagerVest.png b/legacy/public/assets/img/Armor/SalvagerVest.png deleted file mode 100644 index ab39351..0000000 Binary files a/legacy/public/assets/img/Armor/SalvagerVest.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SandBoots.png b/legacy/public/assets/img/Armor/SandBoots.png deleted file mode 100644 index b4a55aa..0000000 Binary files a/legacy/public/assets/img/Armor/SandBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SapphireCirclet.png b/legacy/public/assets/img/Armor/SapphireCirclet.png deleted file mode 100644 index b58c946..0000000 Binary files a/legacy/public/assets/img/Armor/SapphireCirclet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SheiksMask.png b/legacy/public/assets/img/Armor/SheiksMask.png deleted file mode 100644 index b70c772..0000000 Binary files a/legacy/public/assets/img/Armor/SheiksMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SnowBoots.png b/legacy/public/assets/img/Armor/SnowBoots.png deleted file mode 100644 index 37da564..0000000 Binary files a/legacy/public/assets/img/Armor/SnowBoots.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SnowquillHeaddress.png b/legacy/public/assets/img/Armor/SnowquillHeaddress.png deleted file mode 100644 index a344942..0000000 Binary files a/legacy/public/assets/img/Armor/SnowquillHeaddress.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SnowquillTrousers.png b/legacy/public/assets/img/Armor/SnowquillTrousers.png deleted file mode 100644 index bcdd7ef..0000000 Binary files a/legacy/public/assets/img/Armor/SnowquillTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SnowquillTunic.png b/legacy/public/assets/img/Armor/SnowquillTunic.png deleted file mode 100644 index 63d8d4c..0000000 Binary files a/legacy/public/assets/img/Armor/SnowquillTunic.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SoldiersArmor.png b/legacy/public/assets/img/Armor/SoldiersArmor.png deleted file mode 100644 index 5f7e386..0000000 Binary files a/legacy/public/assets/img/Armor/SoldiersArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SoldiersGreaves.png b/legacy/public/assets/img/Armor/SoldiersGreaves.png deleted file mode 100644 index d1e5e7a..0000000 Binary files a/legacy/public/assets/img/Armor/SoldiersGreaves.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/SoldiersHelm.png b/legacy/public/assets/img/Armor/SoldiersHelm.png deleted file mode 100644 index 37c44fc..0000000 Binary files a/legacy/public/assets/img/Armor/SoldiersHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/StealthChestGuard.png b/legacy/public/assets/img/Armor/StealthChestGuard.png deleted file mode 100644 index 517c081..0000000 Binary files a/legacy/public/assets/img/Armor/StealthChestGuard.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/StealthMask.png b/legacy/public/assets/img/Armor/StealthMask.png deleted file mode 100644 index e649df4..0000000 Binary files a/legacy/public/assets/img/Armor/StealthMask.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/StealthTights.png b/legacy/public/assets/img/Armor/StealthTights.png deleted file mode 100644 index 0bd8496..0000000 Binary files a/legacy/public/assets/img/Armor/StealthTights.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ThunderHelm.png b/legacy/public/assets/img/Armor/ThunderHelm.png deleted file mode 100644 index ac3a190..0000000 Binary files a/legacy/public/assets/img/Armor/ThunderHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TinglesHood.png b/legacy/public/assets/img/Armor/TinglesHood.png deleted file mode 100644 index bc9cbcd..0000000 Binary files a/legacy/public/assets/img/Armor/TinglesHood.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TinglesShirt.png b/legacy/public/assets/img/Armor/TinglesShirt.png deleted file mode 100644 index 1d8d401..0000000 Binary files a/legacy/public/assets/img/Armor/TinglesShirt.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TinglesTights.png b/legacy/public/assets/img/Armor/TinglesTights.png deleted file mode 100644 index 0f005d1..0000000 Binary files a/legacy/public/assets/img/Armor/TinglesTights.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TopazEarrings.png b/legacy/public/assets/img/Armor/TopazEarrings.png deleted file mode 100644 index fa28270..0000000 Binary files a/legacy/public/assets/img/Armor/TopazEarrings.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTheHero.png b/legacy/public/assets/img/Armor/TrousersOfTheHero.png deleted file mode 100644 index cfddec0..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTheHero.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTheSky.png b/legacy/public/assets/img/Armor/TrousersOfTheSky.png deleted file mode 100644 index 73c2817..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTheSky.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTheWild.png b/legacy/public/assets/img/Armor/TrousersOfTheWild.png deleted file mode 100644 index ffff934..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTheWild.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTheWind.png b/legacy/public/assets/img/Armor/TrousersOfTheWind.png deleted file mode 100644 index 9ab8a3e..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTheWind.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTime.png b/legacy/public/assets/img/Armor/TrousersOfTime.png deleted file mode 100644 index ceb183d..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTime.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TrousersOfTwilight.png b/legacy/public/assets/img/Armor/TrousersOfTwilight.png deleted file mode 100644 index 96ace0f..0000000 Binary files a/legacy/public/assets/img/Armor/TrousersOfTwilight.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTheHero.png b/legacy/public/assets/img/Armor/TunicOfTheHero.png deleted file mode 100644 index f249843..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTheHero.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTheSky.png b/legacy/public/assets/img/Armor/TunicOfTheSky.png deleted file mode 100644 index 0fa572d..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTheSky.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTheWild.png b/legacy/public/assets/img/Armor/TunicOfTheWild.png deleted file mode 100644 index f858819..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTheWild.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTheWind.png b/legacy/public/assets/img/Armor/TunicOfTheWind.png deleted file mode 100644 index 407fa4e..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTheWind.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTime.png b/legacy/public/assets/img/Armor/TunicOfTime.png deleted file mode 100644 index 61265e1..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTime.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/TunicOfTwilight.png b/legacy/public/assets/img/Armor/TunicOfTwilight.png deleted file mode 100644 index a72f0b7..0000000 Binary files a/legacy/public/assets/img/Armor/TunicOfTwilight.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/VahMedohDivineHelm.png b/legacy/public/assets/img/Armor/VahMedohDivineHelm.png deleted file mode 100644 index 2cabe4b..0000000 Binary files a/legacy/public/assets/img/Armor/VahMedohDivineHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/VahNaborisDivineHelm.png b/legacy/public/assets/img/Armor/VahNaborisDivineHelm.png deleted file mode 100644 index 78d9198..0000000 Binary files a/legacy/public/assets/img/Armor/VahNaborisDivineHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/VahRudaniaDivineHelm.png b/legacy/public/assets/img/Armor/VahRudaniaDivineHelm.png deleted file mode 100644 index 0abac99..0000000 Binary files a/legacy/public/assets/img/Armor/VahRudaniaDivineHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/VahRutaDivineHelm.png b/legacy/public/assets/img/Armor/VahRutaDivineHelm.png deleted file mode 100644 index 7e220e7..0000000 Binary files a/legacy/public/assets/img/Armor/VahRutaDivineHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/WarmDoublet.png b/legacy/public/assets/img/Armor/WarmDoublet.png deleted file mode 100644 index c1918df..0000000 Binary files a/legacy/public/assets/img/Armor/WarmDoublet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/WellWornTrousers.png b/legacy/public/assets/img/Armor/WellWornTrousers.png deleted file mode 100644 index fc81d06..0000000 Binary files a/legacy/public/assets/img/Armor/WellWornTrousers.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ZantsHelmet.png b/legacy/public/assets/img/Armor/ZantsHelmet.png deleted file mode 100644 index a01042d..0000000 Binary files a/legacy/public/assets/img/Armor/ZantsHelmet.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ZoraArmor.png b/legacy/public/assets/img/Armor/ZoraArmor.png deleted file mode 100644 index 3f33f43..0000000 Binary files a/legacy/public/assets/img/Armor/ZoraArmor.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ZoraGreaves.png b/legacy/public/assets/img/Armor/ZoraGreaves.png deleted file mode 100644 index b9912cc..0000000 Binary files a/legacy/public/assets/img/Armor/ZoraGreaves.png and /dev/null differ diff --git a/legacy/public/assets/img/Armor/ZoraHelm.png b/legacy/public/assets/img/Armor/ZoraHelm.png deleted file mode 100644 index a702f59..0000000 Binary files a/legacy/public/assets/img/Armor/ZoraHelm.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/AncientArrow.png b/legacy/public/assets/img/Arrow/AncientArrow.png deleted file mode 100644 index 6b82f69..0000000 Binary files a/legacy/public/assets/img/Arrow/AncientArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/BombArrow.png b/legacy/public/assets/img/Arrow/BombArrow.png deleted file mode 100644 index f63de4c..0000000 Binary files a/legacy/public/assets/img/Arrow/BombArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/FireArrow.png b/legacy/public/assets/img/Arrow/FireArrow.png deleted file mode 100644 index c929ac6..0000000 Binary files a/legacy/public/assets/img/Arrow/FireArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/IceArrow.png b/legacy/public/assets/img/Arrow/IceArrow.png deleted file mode 100644 index ba10f0c..0000000 Binary files a/legacy/public/assets/img/Arrow/IceArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/NormalArrow.png b/legacy/public/assets/img/Arrow/NormalArrow.png deleted file mode 100644 index a8f8c4d..0000000 Binary files a/legacy/public/assets/img/Arrow/NormalArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Arrow/ShockArrow.png b/legacy/public/assets/img/Arrow/ShockArrow.png deleted file mode 100644 index d85eae7..0000000 Binary files a/legacy/public/assets/img/Arrow/ShockArrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/AncientBow.png b/legacy/public/assets/img/Bow/AncientBow.png deleted file mode 100644 index 3d62d47..0000000 Binary files a/legacy/public/assets/img/Bow/AncientBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/BokoBow.png b/legacy/public/assets/img/Bow/BokoBow.png deleted file mode 100644 index a530dbb..0000000 Binary files a/legacy/public/assets/img/Bow/BokoBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/Bow.png b/legacy/public/assets/img/Bow/Bow.png deleted file mode 100644 index 8dcbc1d..0000000 Binary files a/legacy/public/assets/img/Bow/Bow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/BowOfLight.png b/legacy/public/assets/img/Bow/BowOfLight.png deleted file mode 100644 index 2f9aef1..0000000 Binary files a/legacy/public/assets/img/Bow/BowOfLight.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/DragonBoneBokoBow.png b/legacy/public/assets/img/Bow/DragonBoneBokoBow.png deleted file mode 100644 index 4895fc7..0000000 Binary files a/legacy/public/assets/img/Bow/DragonBoneBokoBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/DuplexBow.png b/legacy/public/assets/img/Bow/DuplexBow.png deleted file mode 100644 index e73aa4f..0000000 Binary files a/legacy/public/assets/img/Bow/DuplexBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/FalconBow.png b/legacy/public/assets/img/Bow/FalconBow.png deleted file mode 100644 index 341a35b..0000000 Binary files a/legacy/public/assets/img/Bow/FalconBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/ForestDwellersBow.png b/legacy/public/assets/img/Bow/ForestDwellersBow.png deleted file mode 100644 index 042dfea..0000000 Binary files a/legacy/public/assets/img/Bow/ForestDwellersBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/GoldenBow.png b/legacy/public/assets/img/Bow/GoldenBow.png deleted file mode 100644 index 2acc15e..0000000 Binary files a/legacy/public/assets/img/Bow/GoldenBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/GreatEagleBow.png b/legacy/public/assets/img/Bow/GreatEagleBow.png deleted file mode 100644 index 8c7c581..0000000 Binary files a/legacy/public/assets/img/Bow/GreatEagleBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/KnightsBow.png b/legacy/public/assets/img/Bow/KnightsBow.png deleted file mode 100644 index a876620..0000000 Binary files a/legacy/public/assets/img/Bow/KnightsBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/LizalBow.png b/legacy/public/assets/img/Bow/LizalBow.png deleted file mode 100644 index 3273e6a..0000000 Binary files a/legacy/public/assets/img/Bow/LizalBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/LynelBow.png b/legacy/public/assets/img/Bow/LynelBow.png deleted file mode 100644 index aa1d2ec..0000000 Binary files a/legacy/public/assets/img/Bow/LynelBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/MightyLynelBow.png b/legacy/public/assets/img/Bow/MightyLynelBow.png deleted file mode 100644 index 4dbef9f..0000000 Binary files a/legacy/public/assets/img/Bow/MightyLynelBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/PhrenicBow.png b/legacy/public/assets/img/Bow/PhrenicBow.png deleted file mode 100644 index a9011c9..0000000 Binary files a/legacy/public/assets/img/Bow/PhrenicBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/RoyalBow.png b/legacy/public/assets/img/Bow/RoyalBow.png deleted file mode 100644 index d19d626..0000000 Binary files a/legacy/public/assets/img/Bow/RoyalBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/RoyalGuardsBow.png b/legacy/public/assets/img/Bow/RoyalGuardsBow.png deleted file mode 100644 index 98e3379..0000000 Binary files a/legacy/public/assets/img/Bow/RoyalGuardsBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SavageLynelBow.png b/legacy/public/assets/img/Bow/SavageLynelBow.png deleted file mode 100644 index f7a4ec3..0000000 Binary files a/legacy/public/assets/img/Bow/SavageLynelBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SilverBow.png b/legacy/public/assets/img/Bow/SilverBow.png deleted file mode 100644 index 46c531e..0000000 Binary files a/legacy/public/assets/img/Bow/SilverBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SoldiersBow.png b/legacy/public/assets/img/Bow/SoldiersBow.png deleted file mode 100644 index 9060587..0000000 Binary files a/legacy/public/assets/img/Bow/SoldiersBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SpikedBokoBow.png b/legacy/public/assets/img/Bow/SpikedBokoBow.png deleted file mode 100644 index 4867177..0000000 Binary files a/legacy/public/assets/img/Bow/SpikedBokoBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SteelLizalBow.png b/legacy/public/assets/img/Bow/SteelLizalBow.png deleted file mode 100644 index df19b24..0000000 Binary files a/legacy/public/assets/img/Bow/SteelLizalBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/StrengthenedLizalBow.png b/legacy/public/assets/img/Bow/StrengthenedLizalBow.png deleted file mode 100644 index d088e4c..0000000 Binary files a/legacy/public/assets/img/Bow/StrengthenedLizalBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/SwallowBow.png b/legacy/public/assets/img/Bow/SwallowBow.png deleted file mode 100644 index 70204d2..0000000 Binary files a/legacy/public/assets/img/Bow/SwallowBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/TravelersBow.png b/legacy/public/assets/img/Bow/TravelersBow.png deleted file mode 100644 index b13c63f..0000000 Binary files a/legacy/public/assets/img/Bow/TravelersBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/TwilightBow.png b/legacy/public/assets/img/Bow/TwilightBow.png deleted file mode 100644 index 5913313..0000000 Binary files a/legacy/public/assets/img/Bow/TwilightBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Bow/WoodenBow.png b/legacy/public/assets/img/Bow/WoodenBow.png deleted file mode 100644 index a56d2bf..0000000 Binary files a/legacy/public/assets/img/Bow/WoodenBow.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ApplePie.png b/legacy/public/assets/img/Food/ApplePie.png deleted file mode 100644 index 65406e2..0000000 Binary files a/legacy/public/assets/img/Food/ApplePie.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/BakedApple.png b/legacy/public/assets/img/Food/BakedApple.png deleted file mode 100644 index d78fdce..0000000 Binary files a/legacy/public/assets/img/Food/BakedApple.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/BakedFortifiedPumpkin.png b/legacy/public/assets/img/Food/BakedFortifiedPumpkin.png deleted file mode 100644 index dee57c9..0000000 Binary files a/legacy/public/assets/img/Food/BakedFortifiedPumpkin.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/BakedPalmFruit.png b/legacy/public/assets/img/Food/BakedPalmFruit.png deleted file mode 100644 index 623b06c..0000000 Binary files a/legacy/public/assets/img/Food/BakedPalmFruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/BlackenedCrab.png b/legacy/public/assets/img/Food/BlackenedCrab.png deleted file mode 100644 index fca4f44..0000000 Binary files a/legacy/public/assets/img/Food/BlackenedCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/BlueshellEscargot.png b/legacy/public/assets/img/Food/BlueshellEscargot.png deleted file mode 100644 index d95b694..0000000 Binary files a/legacy/public/assets/img/Food/BlueshellEscargot.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CampfireEgg.png b/legacy/public/assets/img/Food/CampfireEgg.png deleted file mode 100644 index 4e74a68..0000000 Binary files a/legacy/public/assets/img/Food/CampfireEgg.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CarrotCake.png b/legacy/public/assets/img/Food/CarrotCake.png deleted file mode 100644 index bf2f922..0000000 Binary files a/legacy/public/assets/img/Food/CarrotCake.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CarrotStew.png b/legacy/public/assets/img/Food/CarrotStew.png deleted file mode 100644 index 4cf1f31..0000000 Binary files a/legacy/public/assets/img/Food/CarrotStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CharredPepper.png b/legacy/public/assets/img/Food/CharredPepper.png deleted file mode 100644 index 099e5db..0000000 Binary files a/legacy/public/assets/img/Food/CharredPepper.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ChillyElixir.png b/legacy/public/assets/img/Food/ChillyElixir.png deleted file mode 100644 index 809b01a..0000000 Binary files a/legacy/public/assets/img/Food/ChillyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ClamChowder.png b/legacy/public/assets/img/Food/ClamChowder.png deleted file mode 100644 index 51199f0..0000000 Binary files a/legacy/public/assets/img/Food/ClamChowder.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CopiousFriedWildGreens.png b/legacy/public/assets/img/Food/CopiousFriedWildGreens.png deleted file mode 100644 index 4280557..0000000 Binary files a/legacy/public/assets/img/Food/CopiousFriedWildGreens.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CopiousMeatSkewers.png b/legacy/public/assets/img/Food/CopiousMeatSkewers.png deleted file mode 100644 index f5122e3..0000000 Binary files a/legacy/public/assets/img/Food/CopiousMeatSkewers.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CopiousMushroomSkewers.png b/legacy/public/assets/img/Food/CopiousMushroomSkewers.png deleted file mode 100644 index a56a1a5..0000000 Binary files a/legacy/public/assets/img/Food/CopiousMushroomSkewers.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CopiousSeafoodSkewers.png b/legacy/public/assets/img/Food/CopiousSeafoodSkewers.png deleted file mode 100644 index 8e0b221..0000000 Binary files a/legacy/public/assets/img/Food/CopiousSeafoodSkewers.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CopiousSimmeredFruit.png b/legacy/public/assets/img/Food/CopiousSimmeredFruit.png deleted file mode 100644 index a3ee5cb..0000000 Binary files a/legacy/public/assets/img/Food/CopiousSimmeredFruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CrabOmeletWithRice.png b/legacy/public/assets/img/Food/CrabOmeletWithRice.png deleted file mode 100644 index a9896a3..0000000 Binary files a/legacy/public/assets/img/Food/CrabOmeletWithRice.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CrabRisotto.png b/legacy/public/assets/img/Food/CrabRisotto.png deleted file mode 100644 index b5b77d9..0000000 Binary files a/legacy/public/assets/img/Food/CrabRisotto.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CrabStirFry.png b/legacy/public/assets/img/Food/CrabStirFry.png deleted file mode 100644 index 7006b5a..0000000 Binary files a/legacy/public/assets/img/Food/CrabStirFry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CreamOfMushroomSoup.png b/legacy/public/assets/img/Food/CreamOfMushroomSoup.png deleted file mode 100644 index a4d7c04..0000000 Binary files a/legacy/public/assets/img/Food/CreamOfMushroomSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CreamOfVegetableSoup.png b/legacy/public/assets/img/Food/CreamOfVegetableSoup.png deleted file mode 100644 index dd940a1..0000000 Binary files a/legacy/public/assets/img/Food/CreamOfVegetableSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CreamyHeartSoup.png b/legacy/public/assets/img/Food/CreamyHeartSoup.png deleted file mode 100644 index 3256612..0000000 Binary files a/legacy/public/assets/img/Food/CreamyHeartSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CreamyMeatSoup.png b/legacy/public/assets/img/Food/CreamyMeatSoup.png deleted file mode 100644 index 65fef54..0000000 Binary files a/legacy/public/assets/img/Food/CreamyMeatSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CreamySeafoodSoup.png b/legacy/public/assets/img/Food/CreamySeafoodSoup.png deleted file mode 100644 index 1178b18..0000000 Binary files a/legacy/public/assets/img/Food/CreamySeafoodSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CurryPilaf.png b/legacy/public/assets/img/Food/CurryPilaf.png deleted file mode 100644 index 82be501..0000000 Binary files a/legacy/public/assets/img/Food/CurryPilaf.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/CurryRice.png b/legacy/public/assets/img/Food/CurryRice.png deleted file mode 100644 index 2724c9b..0000000 Binary files a/legacy/public/assets/img/Food/CurryRice.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/DubiousFood.png b/legacy/public/assets/img/Food/DubiousFood.png deleted file mode 100644 index a24bc27..0000000 Binary files a/legacy/public/assets/img/Food/DubiousFood.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/EggPudding.png b/legacy/public/assets/img/Food/EggPudding.png deleted file mode 100644 index 07f2619..0000000 Binary files a/legacy/public/assets/img/Food/EggPudding.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/EggTart.png b/legacy/public/assets/img/Food/EggTart.png deleted file mode 100644 index 0b9b42a..0000000 Binary files a/legacy/public/assets/img/Food/EggTart.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ElectroElixir.png b/legacy/public/assets/img/Food/ElectroElixir.png deleted file mode 100644 index ede2c45..0000000 Binary files a/legacy/public/assets/img/Food/ElectroElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/Elixir.png b/legacy/public/assets/img/Food/Elixir.png deleted file mode 100644 index f287a2d..0000000 Binary files a/legacy/public/assets/img/Food/Elixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/EnduringElixir.png b/legacy/public/assets/img/Food/EnduringElixir.png deleted file mode 100644 index 0eeefc7..0000000 Binary files a/legacy/public/assets/img/Food/EnduringElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/EnergizingElixir.png b/legacy/public/assets/img/Food/EnergizingElixir.png deleted file mode 100644 index dbbf078..0000000 Binary files a/legacy/public/assets/img/Food/EnergizingElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FairyTonic.png b/legacy/public/assets/img/Food/FairyTonic.png deleted file mode 100644 index 2f4fad4..0000000 Binary files a/legacy/public/assets/img/Food/FairyTonic.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FireproofElixir.png b/legacy/public/assets/img/Food/FireproofElixir.png deleted file mode 100644 index 1ddd662..0000000 Binary files a/legacy/public/assets/img/Food/FireproofElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FishAndMushroomSkewer.png b/legacy/public/assets/img/Food/FishAndMushroomSkewer.png deleted file mode 100644 index 7c9ba2a..0000000 Binary files a/legacy/public/assets/img/Food/FishAndMushroomSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FishPie.png b/legacy/public/assets/img/Food/FishPie.png deleted file mode 100644 index 4305254..0000000 Binary files a/legacy/public/assets/img/Food/FishPie.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FishSkewer.png b/legacy/public/assets/img/Food/FishSkewer.png deleted file mode 100644 index a5c7274..0000000 Binary files a/legacy/public/assets/img/Food/FishSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FragrantMushroomSaute.png b/legacy/public/assets/img/Food/FragrantMushroomSaute.png deleted file mode 100644 index 2ebbd9e..0000000 Binary files a/legacy/public/assets/img/Food/FragrantMushroomSaute.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FriedBananas.png b/legacy/public/assets/img/Food/FriedBananas.png deleted file mode 100644 index 9391ae0..0000000 Binary files a/legacy/public/assets/img/Food/FriedBananas.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FriedEggAndRice.png b/legacy/public/assets/img/Food/FriedEggAndRice.png deleted file mode 100644 index 87a001c..0000000 Binary files a/legacy/public/assets/img/Food/FriedEggAndRice.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FriedWildGreens.png b/legacy/public/assets/img/Food/FriedWildGreens.png deleted file mode 100644 index 580d068..0000000 Binary files a/legacy/public/assets/img/Food/FriedWildGreens.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenBass.png b/legacy/public/assets/img/Food/FrozenBass.png deleted file mode 100644 index 75098fe..0000000 Binary files a/legacy/public/assets/img/Food/FrozenBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenBirdDrumstick.png b/legacy/public/assets/img/Food/FrozenBirdDrumstick.png deleted file mode 100644 index 733aaa9..0000000 Binary files a/legacy/public/assets/img/Food/FrozenBirdDrumstick.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenBirdThigh.png b/legacy/public/assets/img/Food/FrozenBirdThigh.png deleted file mode 100644 index 84566e8..0000000 Binary files a/legacy/public/assets/img/Food/FrozenBirdThigh.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenCarp.png b/legacy/public/assets/img/Food/FrozenCarp.png deleted file mode 100644 index 7faaff4..0000000 Binary files a/legacy/public/assets/img/Food/FrozenCarp.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenCrab.png b/legacy/public/assets/img/Food/FrozenCrab.png deleted file mode 100644 index e2b163b..0000000 Binary files a/legacy/public/assets/img/Food/FrozenCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenHeartyBass.png b/legacy/public/assets/img/Food/FrozenHeartyBass.png deleted file mode 100644 index 7af6bd3..0000000 Binary files a/legacy/public/assets/img/Food/FrozenHeartyBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenHeartySalmon.png b/legacy/public/assets/img/Food/FrozenHeartySalmon.png deleted file mode 100644 index 9e22915..0000000 Binary files a/legacy/public/assets/img/Food/FrozenHeartySalmon.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenPorgy.png b/legacy/public/assets/img/Food/FrozenPorgy.png deleted file mode 100644 index 5caf988..0000000 Binary files a/legacy/public/assets/img/Food/FrozenPorgy.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenRiverSnail.png b/legacy/public/assets/img/Food/FrozenRiverSnail.png deleted file mode 100644 index f9319fd..0000000 Binary files a/legacy/public/assets/img/Food/FrozenRiverSnail.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenTrout.png b/legacy/public/assets/img/Food/FrozenTrout.png deleted file mode 100644 index 8cb0e8f..0000000 Binary files a/legacy/public/assets/img/Food/FrozenTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FrozenWholeBird.png b/legacy/public/assets/img/Food/FrozenWholeBird.png deleted file mode 100644 index 73faf7a..0000000 Binary files a/legacy/public/assets/img/Food/FrozenWholeBird.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FruitAndMushroomMix.png b/legacy/public/assets/img/Food/FruitAndMushroomMix.png deleted file mode 100644 index 6323775..0000000 Binary files a/legacy/public/assets/img/Food/FruitAndMushroomMix.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/FruitPie.png b/legacy/public/assets/img/Food/FruitPie.png deleted file mode 100644 index cc86e7d..0000000 Binary files a/legacy/public/assets/img/Food/FruitPie.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/Fruitcake.png b/legacy/public/assets/img/Food/Fruitcake.png deleted file mode 100644 index 90de50c..0000000 Binary files a/legacy/public/assets/img/Food/Fruitcake.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GlazedMeat.png b/legacy/public/assets/img/Food/GlazedMeat.png deleted file mode 100644 index 1220418..0000000 Binary files a/legacy/public/assets/img/Food/GlazedMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GlazedMushrooms.png b/legacy/public/assets/img/Food/GlazedMushrooms.png deleted file mode 100644 index bd8c6e7..0000000 Binary files a/legacy/public/assets/img/Food/GlazedMushrooms.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GlazedSeafood.png b/legacy/public/assets/img/Food/GlazedSeafood.png deleted file mode 100644 index a40879d..0000000 Binary files a/legacy/public/assets/img/Food/GlazedSeafood.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GlazedVeggies.png b/legacy/public/assets/img/Food/GlazedVeggies.png deleted file mode 100644 index 37408cd..0000000 Binary files a/legacy/public/assets/img/Food/GlazedVeggies.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetMeatAndRiceBowl.png b/legacy/public/assets/img/Food/GourmetMeatAndRiceBowl.png deleted file mode 100644 index bbdf415..0000000 Binary files a/legacy/public/assets/img/Food/GourmetMeatAndRiceBowl.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetMeatAndSeafoodFry.png b/legacy/public/assets/img/Food/GourmetMeatAndSeafoodFry.png deleted file mode 100644 index a137614..0000000 Binary files a/legacy/public/assets/img/Food/GourmetMeatAndSeafoodFry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetMeatCurry.png b/legacy/public/assets/img/Food/GourmetMeatCurry.png deleted file mode 100644 index e654ca7..0000000 Binary files a/legacy/public/assets/img/Food/GourmetMeatCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetMeatStew.png b/legacy/public/assets/img/Food/GourmetMeatStew.png deleted file mode 100644 index c0fed10..0000000 Binary files a/legacy/public/assets/img/Food/GourmetMeatStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetPoultryCurry.png b/legacy/public/assets/img/Food/GourmetPoultryCurry.png deleted file mode 100644 index d53ff16..0000000 Binary files a/legacy/public/assets/img/Food/GourmetPoultryCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetPoultryPilaf.png b/legacy/public/assets/img/Food/GourmetPoultryPilaf.png deleted file mode 100644 index 2a12153..0000000 Binary files a/legacy/public/assets/img/Food/GourmetPoultryPilaf.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/GourmetSpicedMeatSkewer.png b/legacy/public/assets/img/Food/GourmetSpicedMeatSkewer.png deleted file mode 100644 index c42f7b0..0000000 Binary files a/legacy/public/assets/img/Food/GourmetSpicedMeatSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HardBoiledEgg.png b/legacy/public/assets/img/Food/HardBoiledEgg.png deleted file mode 100644 index c659881..0000000 Binary files a/legacy/public/assets/img/Food/HardBoiledEgg.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HastyElixir.png b/legacy/public/assets/img/Food/HastyElixir.png deleted file mode 100644 index 99d51b9..0000000 Binary files a/legacy/public/assets/img/Food/HastyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HeartyElixir.png b/legacy/public/assets/img/Food/HeartyElixir.png deleted file mode 100644 index 7ea873b..0000000 Binary files a/legacy/public/assets/img/Food/HeartyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HerbSaute.png b/legacy/public/assets/img/Food/HerbSaute.png deleted file mode 100644 index a1b03bb..0000000 Binary files a/legacy/public/assets/img/Food/HerbSaute.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HoneyCandy.png b/legacy/public/assets/img/Food/HoneyCandy.png deleted file mode 100644 index d92738f..0000000 Binary files a/legacy/public/assets/img/Food/HoneyCandy.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HoneyCrepe.png b/legacy/public/assets/img/Food/HoneyCrepe.png deleted file mode 100644 index 01f5144..0000000 Binary files a/legacy/public/assets/img/Food/HoneyCrepe.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HoneyedApple.png b/legacy/public/assets/img/Food/HoneyedApple.png deleted file mode 100644 index 9fc2100..0000000 Binary files a/legacy/public/assets/img/Food/HoneyedApple.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HoneyedFruits.png b/legacy/public/assets/img/Food/HoneyedFruits.png deleted file mode 100644 index 2353d5a..0000000 Binary files a/legacy/public/assets/img/Food/HoneyedFruits.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/HotButteredApple.png b/legacy/public/assets/img/Food/HotButteredApple.png deleted file mode 100644 index 21a2526..0000000 Binary files a/legacy/public/assets/img/Food/HotButteredApple.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/IcyGourmetMeat.png b/legacy/public/assets/img/Food/IcyGourmetMeat.png deleted file mode 100644 index 899ed2e..0000000 Binary files a/legacy/public/assets/img/Food/IcyGourmetMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/IcyHeartyBlueshellSnail.png b/legacy/public/assets/img/Food/IcyHeartyBlueshellSnail.png deleted file mode 100644 index fe43661..0000000 Binary files a/legacy/public/assets/img/Food/IcyHeartyBlueshellSnail.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/IcyMeat.png b/legacy/public/assets/img/Food/IcyMeat.png deleted file mode 100644 index c4198dd..0000000 Binary files a/legacy/public/assets/img/Food/IcyMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/IcyPrimeMeat.png b/legacy/public/assets/img/Food/IcyPrimeMeat.png deleted file mode 100644 index e7e2963..0000000 Binary files a/legacy/public/assets/img/Food/IcyPrimeMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatAndMushroomSkewer.png b/legacy/public/assets/img/Food/MeatAndMushroomSkewer.png deleted file mode 100644 index f073d98..0000000 Binary files a/legacy/public/assets/img/Food/MeatAndMushroomSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatAndRiceBowl.png b/legacy/public/assets/img/Food/MeatAndRiceBowl.png deleted file mode 100644 index 5398968..0000000 Binary files a/legacy/public/assets/img/Food/MeatAndRiceBowl.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatAndSeafoodFry.png b/legacy/public/assets/img/Food/MeatAndSeafoodFry.png deleted file mode 100644 index 92b26ac..0000000 Binary files a/legacy/public/assets/img/Food/MeatAndSeafoodFry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatCurry.png b/legacy/public/assets/img/Food/MeatCurry.png deleted file mode 100644 index 054edb9..0000000 Binary files a/legacy/public/assets/img/Food/MeatCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatPie.png b/legacy/public/assets/img/Food/MeatPie.png deleted file mode 100644 index 6318cba..0000000 Binary files a/legacy/public/assets/img/Food/MeatPie.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatSkewer.png b/legacy/public/assets/img/Food/MeatSkewer.png deleted file mode 100644 index 41a455c..0000000 Binary files a/legacy/public/assets/img/Food/MeatSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatStew.png b/legacy/public/assets/img/Food/MeatStew.png deleted file mode 100644 index 4c96362..0000000 Binary files a/legacy/public/assets/img/Food/MeatStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatStuffedPumpkin.png b/legacy/public/assets/img/Food/MeatStuffedPumpkin.png deleted file mode 100644 index 3bf1072..0000000 Binary files a/legacy/public/assets/img/Food/MeatStuffedPumpkin.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MeatyRiceBalls.png b/legacy/public/assets/img/Food/MeatyRiceBalls.png deleted file mode 100644 index f4b98fb..0000000 Binary files a/legacy/public/assets/img/Food/MeatyRiceBalls.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MightyElixir.png b/legacy/public/assets/img/Food/MightyElixir.png deleted file mode 100644 index c000f0d..0000000 Binary files a/legacy/public/assets/img/Food/MightyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MonsterCake.png b/legacy/public/assets/img/Food/MonsterCake.png deleted file mode 100644 index ea8fad6..0000000 Binary files a/legacy/public/assets/img/Food/MonsterCake.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MonsterCurry.png b/legacy/public/assets/img/Food/MonsterCurry.png deleted file mode 100644 index f9a28b2..0000000 Binary files a/legacy/public/assets/img/Food/MonsterCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MonsterRiceBalls.png b/legacy/public/assets/img/Food/MonsterRiceBalls.png deleted file mode 100644 index b950a0f..0000000 Binary files a/legacy/public/assets/img/Food/MonsterRiceBalls.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MonsterSoup.png b/legacy/public/assets/img/Food/MonsterSoup.png deleted file mode 100644 index 1dd5159..0000000 Binary files a/legacy/public/assets/img/Food/MonsterSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MonsterStew.png b/legacy/public/assets/img/Food/MonsterStew.png deleted file mode 100644 index 005187e..0000000 Binary files a/legacy/public/assets/img/Food/MonsterStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MushroomOmelet.png b/legacy/public/assets/img/Food/MushroomOmelet.png deleted file mode 100644 index 956291c..0000000 Binary files a/legacy/public/assets/img/Food/MushroomOmelet.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MushroomRiceBalls.png b/legacy/public/assets/img/Food/MushroomRiceBalls.png deleted file mode 100644 index 133cf40..0000000 Binary files a/legacy/public/assets/img/Food/MushroomRiceBalls.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MushroomRisotto.png b/legacy/public/assets/img/Food/MushroomRisotto.png deleted file mode 100644 index 1fbbca3..0000000 Binary files a/legacy/public/assets/img/Food/MushroomRisotto.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/MushroomSkewer.png b/legacy/public/assets/img/Food/MushroomSkewer.png deleted file mode 100644 index f31229b..0000000 Binary files a/legacy/public/assets/img/Food/MushroomSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/Nutcake.png b/legacy/public/assets/img/Food/Nutcake.png deleted file mode 100644 index 72446db..0000000 Binary files a/legacy/public/assets/img/Food/Nutcake.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/Omelet.png b/legacy/public/assets/img/Food/Omelet.png deleted file mode 100644 index 4e478b0..0000000 Binary files a/legacy/public/assets/img/Food/Omelet.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PepperSeafood.png b/legacy/public/assets/img/Food/PepperSeafood.png deleted file mode 100644 index 62d3b93..0000000 Binary files a/legacy/public/assets/img/Food/PepperSeafood.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PepperSteak.png b/legacy/public/assets/img/Food/PepperSteak.png deleted file mode 100644 index 15adc23..0000000 Binary files a/legacy/public/assets/img/Food/PepperSteak.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PlainCrepe.png b/legacy/public/assets/img/Food/PlainCrepe.png deleted file mode 100644 index 49fb4d3..0000000 Binary files a/legacy/public/assets/img/Food/PlainCrepe.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PorgyMeuniere.png b/legacy/public/assets/img/Food/PorgyMeuniere.png deleted file mode 100644 index 7938ca6..0000000 Binary files a/legacy/public/assets/img/Food/PorgyMeuniere.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PoultryCurry.png b/legacy/public/assets/img/Food/PoultryCurry.png deleted file mode 100644 index b23f74b..0000000 Binary files a/legacy/public/assets/img/Food/PoultryCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PoultryPilaf.png b/legacy/public/assets/img/Food/PoultryPilaf.png deleted file mode 100644 index f6c0c91..0000000 Binary files a/legacy/public/assets/img/Food/PoultryPilaf.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimeMeatAndRiceBowl.png b/legacy/public/assets/img/Food/PrimeMeatAndRiceBowl.png deleted file mode 100644 index 981b567..0000000 Binary files a/legacy/public/assets/img/Food/PrimeMeatAndRiceBowl.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimeMeatAndSeafoodFry.png b/legacy/public/assets/img/Food/PrimeMeatAndSeafoodFry.png deleted file mode 100644 index cd1014f..0000000 Binary files a/legacy/public/assets/img/Food/PrimeMeatAndSeafoodFry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimeMeatCurry.png b/legacy/public/assets/img/Food/PrimeMeatCurry.png deleted file mode 100644 index 74f4925..0000000 Binary files a/legacy/public/assets/img/Food/PrimeMeatCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimeMeatStew.png b/legacy/public/assets/img/Food/PrimeMeatStew.png deleted file mode 100644 index fc02b80..0000000 Binary files a/legacy/public/assets/img/Food/PrimeMeatStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimePoultryCurry.png b/legacy/public/assets/img/Food/PrimePoultryCurry.png deleted file mode 100644 index e344a32..0000000 Binary files a/legacy/public/assets/img/Food/PrimePoultryCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimePoultryPilaf.png b/legacy/public/assets/img/Food/PrimePoultryPilaf.png deleted file mode 100644 index 6087e4e..0000000 Binary files a/legacy/public/assets/img/Food/PrimePoultryPilaf.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PrimeSpicedMeatSkewer.png b/legacy/public/assets/img/Food/PrimeSpicedMeatSkewer.png deleted file mode 100644 index 86cc321..0000000 Binary files a/legacy/public/assets/img/Food/PrimeSpicedMeatSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PumpkinPie.png b/legacy/public/assets/img/Food/PumpkinPie.png deleted file mode 100644 index 833282d..0000000 Binary files a/legacy/public/assets/img/Food/PumpkinPie.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/PumpkinStew.png b/legacy/public/assets/img/Food/PumpkinStew.png deleted file mode 100644 index fdcb607..0000000 Binary files a/legacy/public/assets/img/Food/PumpkinStew.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedAcorn.png b/legacy/public/assets/img/Food/RoastedAcorn.png deleted file mode 100644 index 8bf7348..0000000 Binary files a/legacy/public/assets/img/Food/RoastedAcorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedArmoranth.png b/legacy/public/assets/img/Food/RoastedArmoranth.png deleted file mode 100644 index 4cf7497..0000000 Binary files a/legacy/public/assets/img/Food/RoastedArmoranth.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedBass.png b/legacy/public/assets/img/Food/RoastedBass.png deleted file mode 100644 index da9d1ad..0000000 Binary files a/legacy/public/assets/img/Food/RoastedBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedBigRadish.png b/legacy/public/assets/img/Food/RoastedBigRadish.png deleted file mode 100644 index 6e3374c..0000000 Binary files a/legacy/public/assets/img/Food/RoastedBigRadish.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedBirdDrumstick.png b/legacy/public/assets/img/Food/RoastedBirdDrumstick.png deleted file mode 100644 index c5583c2..0000000 Binary files a/legacy/public/assets/img/Food/RoastedBirdDrumstick.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedBirdThigh.png b/legacy/public/assets/img/Food/RoastedBirdThigh.png deleted file mode 100644 index 9cd80f8..0000000 Binary files a/legacy/public/assets/img/Food/RoastedBirdThigh.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedCarp.png b/legacy/public/assets/img/Food/RoastedCarp.png deleted file mode 100644 index e75ec58..0000000 Binary files a/legacy/public/assets/img/Food/RoastedCarp.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedEnduraCarrot.png b/legacy/public/assets/img/Food/RoastedEnduraCarrot.png deleted file mode 100644 index cf7ac6c..0000000 Binary files a/legacy/public/assets/img/Food/RoastedEnduraCarrot.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedHeartyBass.png b/legacy/public/assets/img/Food/RoastedHeartyBass.png deleted file mode 100644 index 5713460..0000000 Binary files a/legacy/public/assets/img/Food/RoastedHeartyBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedHeartyDurian.png b/legacy/public/assets/img/Food/RoastedHeartyDurian.png deleted file mode 100644 index 0d82069..0000000 Binary files a/legacy/public/assets/img/Food/RoastedHeartyDurian.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedHeartySalmon.png b/legacy/public/assets/img/Food/RoastedHeartySalmon.png deleted file mode 100644 index e015d42..0000000 Binary files a/legacy/public/assets/img/Food/RoastedHeartySalmon.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedHydromelon.png b/legacy/public/assets/img/Food/RoastedHydromelon.png deleted file mode 100644 index 32ff855..0000000 Binary files a/legacy/public/assets/img/Food/RoastedHydromelon.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedLotusSeeds.png b/legacy/public/assets/img/Food/RoastedLotusSeeds.png deleted file mode 100644 index e1c5ec0..0000000 Binary files a/legacy/public/assets/img/Food/RoastedLotusSeeds.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedMightyBananas.png b/legacy/public/assets/img/Food/RoastedMightyBananas.png deleted file mode 100644 index 2046493..0000000 Binary files a/legacy/public/assets/img/Food/RoastedMightyBananas.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedMightyThistle.png b/legacy/public/assets/img/Food/RoastedMightyThistle.png deleted file mode 100644 index e5ba2ae..0000000 Binary files a/legacy/public/assets/img/Food/RoastedMightyThistle.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedPorgy.png b/legacy/public/assets/img/Food/RoastedPorgy.png deleted file mode 100644 index 18b364d..0000000 Binary files a/legacy/public/assets/img/Food/RoastedPorgy.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedRadish.png b/legacy/public/assets/img/Food/RoastedRadish.png deleted file mode 100644 index 1773258..0000000 Binary files a/legacy/public/assets/img/Food/RoastedRadish.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedSwiftCarrot.png b/legacy/public/assets/img/Food/RoastedSwiftCarrot.png deleted file mode 100644 index fc18c0d..0000000 Binary files a/legacy/public/assets/img/Food/RoastedSwiftCarrot.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedTreeNut.png b/legacy/public/assets/img/Food/RoastedTreeNut.png deleted file mode 100644 index a0ee91a..0000000 Binary files a/legacy/public/assets/img/Food/RoastedTreeNut.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedTrout.png b/legacy/public/assets/img/Food/RoastedTrout.png deleted file mode 100644 index e66e9da..0000000 Binary files a/legacy/public/assets/img/Food/RoastedTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedVoltfruit.png b/legacy/public/assets/img/Food/RoastedVoltfruit.png deleted file mode 100644 index 6b523a7..0000000 Binary files a/legacy/public/assets/img/Food/RoastedVoltfruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedWholeBird.png b/legacy/public/assets/img/Food/RoastedWholeBird.png deleted file mode 100644 index 3fa070e..0000000 Binary files a/legacy/public/assets/img/Food/RoastedWholeBird.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RoastedWildberry.png b/legacy/public/assets/img/Food/RoastedWildberry.png deleted file mode 100644 index cd283be..0000000 Binary files a/legacy/public/assets/img/Food/RoastedWildberry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/RockHardFood.png b/legacy/public/assets/img/Food/RockHardFood.png deleted file mode 100644 index e126f65..0000000 Binary files a/legacy/public/assets/img/Food/RockHardFood.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SalmonMeuniere.png b/legacy/public/assets/img/Food/SalmonMeuniere.png deleted file mode 100644 index beb8c7e..0000000 Binary files a/legacy/public/assets/img/Food/SalmonMeuniere.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SalmonRisotto.png b/legacy/public/assets/img/Food/SalmonRisotto.png deleted file mode 100644 index 5b4eefa..0000000 Binary files a/legacy/public/assets/img/Food/SalmonRisotto.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledCrab.png b/legacy/public/assets/img/Food/SaltGrilledCrab.png deleted file mode 100644 index 67050db..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledFish.png b/legacy/public/assets/img/Food/SaltGrilledFish.png deleted file mode 100644 index 3a9d17e..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledFish.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledGourmetMeat.png b/legacy/public/assets/img/Food/SaltGrilledGourmetMeat.png deleted file mode 100644 index 519c339..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledGourmetMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledGreens.png b/legacy/public/assets/img/Food/SaltGrilledGreens.png deleted file mode 100644 index 32b24f2..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledGreens.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledMeat.png b/legacy/public/assets/img/Food/SaltGrilledMeat.png deleted file mode 100644 index 74eca71..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledMushrooms.png b/legacy/public/assets/img/Food/SaltGrilledMushrooms.png deleted file mode 100644 index ee62ea6..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledMushrooms.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SaltGrilledPrimeMeat.png b/legacy/public/assets/img/Food/SaltGrilledPrimeMeat.png deleted file mode 100644 index 0682359..0000000 Binary files a/legacy/public/assets/img/Food/SaltGrilledPrimeMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SauteedNuts.png b/legacy/public/assets/img/Food/SauteedNuts.png deleted file mode 100644 index b79a7df..0000000 Binary files a/legacy/public/assets/img/Food/SauteedNuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SauteedPeppers.png b/legacy/public/assets/img/Food/SauteedPeppers.png deleted file mode 100644 index b4b04b3..0000000 Binary files a/legacy/public/assets/img/Food/SauteedPeppers.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodCurry.png b/legacy/public/assets/img/Food/SeafoodCurry.png deleted file mode 100644 index 68a0591..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodFriedRice.png b/legacy/public/assets/img/Food/SeafoodFriedRice.png deleted file mode 100644 index f682bb8..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodFriedRice.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodMeuniere.png b/legacy/public/assets/img/Food/SeafoodMeuniere.png deleted file mode 100644 index 3dfa7de..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodMeuniere.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodPaella.png b/legacy/public/assets/img/Food/SeafoodPaella.png deleted file mode 100644 index d19f51d..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodPaella.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodRiceBalls.png b/legacy/public/assets/img/Food/SeafoodRiceBalls.png deleted file mode 100644 index 3f29921..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodRiceBalls.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SeafoodSkewer.png b/legacy/public/assets/img/Food/SeafoodSkewer.png deleted file mode 100644 index ade7c9f..0000000 Binary files a/legacy/public/assets/img/Food/SeafoodSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SearedGourmetSteak.png b/legacy/public/assets/img/Food/SearedGourmetSteak.png deleted file mode 100644 index 07d7cc6..0000000 Binary files a/legacy/public/assets/img/Food/SearedGourmetSteak.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SearedPrimeSteak.png b/legacy/public/assets/img/Food/SearedPrimeSteak.png deleted file mode 100644 index b72501e..0000000 Binary files a/legacy/public/assets/img/Food/SearedPrimeSteak.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SearedSteak.png b/legacy/public/assets/img/Food/SearedSteak.png deleted file mode 100644 index 1afe004..0000000 Binary files a/legacy/public/assets/img/Food/SearedSteak.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SimmeredFruit.png b/legacy/public/assets/img/Food/SimmeredFruit.png deleted file mode 100644 index 2a85991..0000000 Binary files a/legacy/public/assets/img/Food/SimmeredFruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SneakyElixir.png b/legacy/public/assets/img/Food/SneakyElixir.png deleted file mode 100644 index f0240bc..0000000 Binary files a/legacy/public/assets/img/Food/SneakyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SneakyRiverEscargot.png b/legacy/public/assets/img/Food/SneakyRiverEscargot.png deleted file mode 100644 index 61e62fa..0000000 Binary files a/legacy/public/assets/img/Food/SneakyRiverEscargot.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SpicedMeatSkewer.png b/legacy/public/assets/img/Food/SpicedMeatSkewer.png deleted file mode 100644 index 49c2820..0000000 Binary files a/legacy/public/assets/img/Food/SpicedMeatSkewer.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SpicyElixir.png b/legacy/public/assets/img/Food/SpicyElixir.png deleted file mode 100644 index b9988f1..0000000 Binary files a/legacy/public/assets/img/Food/SpicyElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SteamedFish.png b/legacy/public/assets/img/Food/SteamedFish.png deleted file mode 100644 index f43acf1..0000000 Binary files a/legacy/public/assets/img/Food/SteamedFish.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SteamedFruit.png b/legacy/public/assets/img/Food/SteamedFruit.png deleted file mode 100644 index c6a465b..0000000 Binary files a/legacy/public/assets/img/Food/SteamedFruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SteamedMeat.png b/legacy/public/assets/img/Food/SteamedMeat.png deleted file mode 100644 index 6fb612f..0000000 Binary files a/legacy/public/assets/img/Food/SteamedMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/SteamedMushrooms.png b/legacy/public/assets/img/Food/SteamedMushrooms.png deleted file mode 100644 index 3c4028e..0000000 Binary files a/legacy/public/assets/img/Food/SteamedMushrooms.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastedBigHeartyTruffle.png b/legacy/public/assets/img/Food/ToastedBigHeartyTruffle.png deleted file mode 100644 index c0f8bbc..0000000 Binary files a/legacy/public/assets/img/Food/ToastedBigHeartyTruffle.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastedHeartyTruffle.png b/legacy/public/assets/img/Food/ToastedHeartyTruffle.png deleted file mode 100644 index 9f22551..0000000 Binary files a/legacy/public/assets/img/Food/ToastedHeartyTruffle.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyChillshroom.png b/legacy/public/assets/img/Food/ToastyChillshroom.png deleted file mode 100644 index 393044b..0000000 Binary files a/legacy/public/assets/img/Food/ToastyChillshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyEnduraShroom.png b/legacy/public/assets/img/Food/ToastyEnduraShroom.png deleted file mode 100644 index 6d146ba..0000000 Binary files a/legacy/public/assets/img/Food/ToastyEnduraShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyHylianShroom.png b/legacy/public/assets/img/Food/ToastyHylianShroom.png deleted file mode 100644 index bd54a66..0000000 Binary files a/legacy/public/assets/img/Food/ToastyHylianShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyIronshroom.png b/legacy/public/assets/img/Food/ToastyIronshroom.png deleted file mode 100644 index 1e54c4e..0000000 Binary files a/legacy/public/assets/img/Food/ToastyIronshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyRazorshroom.png b/legacy/public/assets/img/Food/ToastyRazorshroom.png deleted file mode 100644 index 4e55f7c..0000000 Binary files a/legacy/public/assets/img/Food/ToastyRazorshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyRushroom.png b/legacy/public/assets/img/Food/ToastyRushroom.png deleted file mode 100644 index 359250b..0000000 Binary files a/legacy/public/assets/img/Food/ToastyRushroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastySilentShroom.png b/legacy/public/assets/img/Food/ToastySilentShroom.png deleted file mode 100644 index 6a61e2d..0000000 Binary files a/legacy/public/assets/img/Food/ToastySilentShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyStamellaShroom.png b/legacy/public/assets/img/Food/ToastyStamellaShroom.png deleted file mode 100644 index e07c8af..0000000 Binary files a/legacy/public/assets/img/Food/ToastyStamellaShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastySunshroom.png b/legacy/public/assets/img/Food/ToastySunshroom.png deleted file mode 100644 index 0f3cc6f..0000000 Binary files a/legacy/public/assets/img/Food/ToastySunshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToastyZapshroom.png b/legacy/public/assets/img/Food/ToastyZapshroom.png deleted file mode 100644 index 37b4d98..0000000 Binary files a/legacy/public/assets/img/Food/ToastyZapshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/ToughElixir.png b/legacy/public/assets/img/Food/ToughElixir.png deleted file mode 100644 index a3213d2..0000000 Binary files a/legacy/public/assets/img/Food/ToughElixir.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/VegetableCurry.png b/legacy/public/assets/img/Food/VegetableCurry.png deleted file mode 100644 index c70a8a9..0000000 Binary files a/legacy/public/assets/img/Food/VegetableCurry.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/VegetableOmelet.png b/legacy/public/assets/img/Food/VegetableOmelet.png deleted file mode 100644 index 19cd510..0000000 Binary files a/legacy/public/assets/img/Food/VegetableOmelet.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/VegetableRisotto.png b/legacy/public/assets/img/Food/VegetableRisotto.png deleted file mode 100644 index c8abf48..0000000 Binary files a/legacy/public/assets/img/Food/VegetableRisotto.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/VeggieCreamSoup.png b/legacy/public/assets/img/Food/VeggieCreamSoup.png deleted file mode 100644 index bf30f2e..0000000 Binary files a/legacy/public/assets/img/Food/VeggieCreamSoup.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/VeggieRiceBalls.png b/legacy/public/assets/img/Food/VeggieRiceBalls.png deleted file mode 100644 index 5aaffc2..0000000 Binary files a/legacy/public/assets/img/Food/VeggieRiceBalls.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/WarmMilk.png b/legacy/public/assets/img/Food/WarmMilk.png deleted file mode 100644 index a65309a..0000000 Binary files a/legacy/public/assets/img/Food/WarmMilk.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/WheatBread.png b/legacy/public/assets/img/Food/WheatBread.png deleted file mode 100644 index 941b5d6..0000000 Binary files a/legacy/public/assets/img/Food/WheatBread.png and /dev/null differ diff --git a/legacy/public/assets/img/Food/WildberryCrepe.png b/legacy/public/assets/img/Food/WildberryCrepe.png deleted file mode 100644 index cc29d87..0000000 Binary files a/legacy/public/assets/img/Food/WildberryCrepe.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/AncientBridle.png b/legacy/public/assets/img/Key/AncientBridle.png deleted file mode 100644 index f5b7609..0000000 Binary files a/legacy/public/assets/img/Key/AncientBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/AncientSaddle.png b/legacy/public/assets/img/Key/AncientSaddle.png deleted file mode 100644 index 4136d86..0000000 Binary files a/legacy/public/assets/img/Key/AncientSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/ClassifiedEnvelope.png b/legacy/public/assets/img/Key/ClassifiedEnvelope.png deleted file mode 100644 index a362418..0000000 Binary files a/legacy/public/assets/img/Key/ClassifiedEnvelope.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/DaruksProtection.png b/legacy/public/assets/img/Key/DaruksProtection.png deleted file mode 100644 index 276f4b5..0000000 Binary files a/legacy/public/assets/img/Key/DaruksProtection.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/DaruksProtectionDisabled.png b/legacy/public/assets/img/Key/DaruksProtectionDisabled.png deleted file mode 100644 index 00ab23b..0000000 Binary files a/legacy/public/assets/img/Key/DaruksProtectionDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/DaruksProtectionPlus.png b/legacy/public/assets/img/Key/DaruksProtectionPlus.png deleted file mode 100644 index dc5cbef..0000000 Binary files a/legacy/public/assets/img/Key/DaruksProtectionPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/DaruksProtectionPlusDisabled.png b/legacy/public/assets/img/Key/DaruksProtectionPlusDisabled.png deleted file mode 100644 index f2d2c3e..0000000 Binary files a/legacy/public/assets/img/Key/DaruksProtectionPlusDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/ExtravagantBridle.png b/legacy/public/assets/img/Key/ExtravagantBridle.png deleted file mode 100644 index 4b3cded..0000000 Binary files a/legacy/public/assets/img/Key/ExtravagantBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/ExtravagantSaddle.png b/legacy/public/assets/img/Key/ExtravagantSaddle.png deleted file mode 100644 index 8d69873..0000000 Binary files a/legacy/public/assets/img/Key/ExtravagantSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/HestusGift.png b/legacy/public/assets/img/Key/HestusGift.png deleted file mode 100644 index 58ba61a..0000000 Binary files a/legacy/public/assets/img/Key/HestusGift.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/HestusMaracas.png b/legacy/public/assets/img/Key/HestusMaracas.png deleted file mode 100644 index 076da5a..0000000 Binary files a/legacy/public/assets/img/Key/HestusMaracas.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/KnightsBridle.png b/legacy/public/assets/img/Key/KnightsBridle.png deleted file mode 100644 index 9ee65a6..0000000 Binary files a/legacy/public/assets/img/Key/KnightsBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/KnightsSaddle.png b/legacy/public/assets/img/Key/KnightsSaddle.png deleted file mode 100644 index 04cf883..0000000 Binary files a/legacy/public/assets/img/Key/KnightsSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/KorokSeed.png b/legacy/public/assets/img/Key/KorokSeed.png deleted file mode 100644 index cd893a5..0000000 Binary files a/legacy/public/assets/img/Key/KorokSeed.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MedalOfHonorHinox.png b/legacy/public/assets/img/Key/MedalOfHonorHinox.png deleted file mode 100644 index a224341..0000000 Binary files a/legacy/public/assets/img/Key/MedalOfHonorHinox.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MedalOfHonorMolduga.png b/legacy/public/assets/img/Key/MedalOfHonorMolduga.png deleted file mode 100644 index 88a8918..0000000 Binary files a/legacy/public/assets/img/Key/MedalOfHonorMolduga.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MedalOfHonorTalus.png b/legacy/public/assets/img/Key/MedalOfHonorTalus.png deleted file mode 100644 index 17c2e84..0000000 Binary files a/legacy/public/assets/img/Key/MedalOfHonorTalus.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MedohsEmblem.png b/legacy/public/assets/img/Key/MedohsEmblem.png deleted file mode 100644 index 23a38be..0000000 Binary files a/legacy/public/assets/img/Key/MedohsEmblem.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MiphasGrace.png b/legacy/public/assets/img/Key/MiphasGrace.png deleted file mode 100644 index f8f5074..0000000 Binary files a/legacy/public/assets/img/Key/MiphasGrace.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MiphasGraceDisabled.png b/legacy/public/assets/img/Key/MiphasGraceDisabled.png deleted file mode 100644 index a182bde..0000000 Binary files a/legacy/public/assets/img/Key/MiphasGraceDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MiphasGracePlus.png b/legacy/public/assets/img/Key/MiphasGracePlus.png deleted file mode 100644 index 5f3d80f..0000000 Binary files a/legacy/public/assets/img/Key/MiphasGracePlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MiphasGracePlusDisabled.png b/legacy/public/assets/img/Key/MiphasGracePlusDisabled.png deleted file mode 100644 index 648bb95..0000000 Binary files a/legacy/public/assets/img/Key/MiphasGracePlusDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MonsterBridle.png b/legacy/public/assets/img/Key/MonsterBridle.png deleted file mode 100644 index b2fa2f9..0000000 Binary files a/legacy/public/assets/img/Key/MonsterBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/MonsterSaddle.png b/legacy/public/assets/img/Key/MonsterSaddle.png deleted file mode 100644 index 47b0500..0000000 Binary files a/legacy/public/assets/img/Key/MonsterSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/NaborissEmblem.png b/legacy/public/assets/img/Key/NaborissEmblem.png deleted file mode 100644 index fb49afe..0000000 Binary files a/legacy/public/assets/img/Key/NaborissEmblem.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/Paraglider.png b/legacy/public/assets/img/Key/Paraglider.png deleted file mode 100644 index 9f7e3de..0000000 Binary files a/legacy/public/assets/img/Key/Paraglider.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/PictureOfTheChampions.png b/legacy/public/assets/img/Key/PictureOfTheChampions.png deleted file mode 100644 index a378160..0000000 Binary files a/legacy/public/assets/img/Key/PictureOfTheChampions.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RevalisGale.png b/legacy/public/assets/img/Key/RevalisGale.png deleted file mode 100644 index 5349613..0000000 Binary files a/legacy/public/assets/img/Key/RevalisGale.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RevalisGaleDisabled.png b/legacy/public/assets/img/Key/RevalisGaleDisabled.png deleted file mode 100644 index bd4bc0d..0000000 Binary files a/legacy/public/assets/img/Key/RevalisGaleDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RevalisGalePlus.png b/legacy/public/assets/img/Key/RevalisGalePlus.png deleted file mode 100644 index c01ca1f..0000000 Binary files a/legacy/public/assets/img/Key/RevalisGalePlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RevalisGalePlusDisabled.png b/legacy/public/assets/img/Key/RevalisGalePlusDisabled.png deleted file mode 100644 index 5d28bc5..0000000 Binary files a/legacy/public/assets/img/Key/RevalisGalePlusDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RoyalBridle.png b/legacy/public/assets/img/Key/RoyalBridle.png deleted file mode 100644 index bbe52f2..0000000 Binary files a/legacy/public/assets/img/Key/RoyalBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RoyalSaddle.png b/legacy/public/assets/img/Key/RoyalSaddle.png deleted file mode 100644 index b2e2cda..0000000 Binary files a/legacy/public/assets/img/Key/RoyalSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RudaniasEmblem.png b/legacy/public/assets/img/Key/RudaniasEmblem.png deleted file mode 100644 index 91b6efb..0000000 Binary files a/legacy/public/assets/img/Key/RudaniasEmblem.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/RutasEmblem.png b/legacy/public/assets/img/Key/RutasEmblem.png deleted file mode 100644 index 6e72bf1..0000000 Binary files a/legacy/public/assets/img/Key/RutasEmblem.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/SheikahSlate.png b/legacy/public/assets/img/Key/SheikahSlate.png deleted file mode 100644 index 5f86b15..0000000 Binary files a/legacy/public/assets/img/Key/SheikahSlate.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/SpiritOrb.png b/legacy/public/assets/img/Key/SpiritOrb.png deleted file mode 100644 index 00e8ea4..0000000 Binary files a/legacy/public/assets/img/Key/SpiritOrb.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/SpiritOrbAnimated.webp b/legacy/public/assets/img/Key/SpiritOrbAnimated.webp deleted file mode 100644 index 31cb3fd..0000000 Binary files a/legacy/public/assets/img/Key/SpiritOrbAnimated.webp and /dev/null differ diff --git a/legacy/public/assets/img/Key/ThunderHelmKey.png b/legacy/public/assets/img/Key/ThunderHelmKey.png deleted file mode 100644 index 8365fa4..0000000 Binary files a/legacy/public/assets/img/Key/ThunderHelmKey.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/TravelMedallion.png b/legacy/public/assets/img/Key/TravelMedallion.png deleted file mode 100644 index c216dc0..0000000 Binary files a/legacy/public/assets/img/Key/TravelMedallion.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/TravelMedallionAnimated.webp b/legacy/public/assets/img/Key/TravelMedallionAnimated.webp deleted file mode 100644 index b3e3c8c..0000000 Binary files a/legacy/public/assets/img/Key/TravelMedallionAnimated.webp and /dev/null differ diff --git a/legacy/public/assets/img/Key/TravelersBridle.png b/legacy/public/assets/img/Key/TravelersBridle.png deleted file mode 100644 index ef6a809..0000000 Binary files a/legacy/public/assets/img/Key/TravelersBridle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/TravelersSaddle.png b/legacy/public/assets/img/Key/TravelersSaddle.png deleted file mode 100644 index e2e2a8d..0000000 Binary files a/legacy/public/assets/img/Key/TravelersSaddle.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/UrbosasFury.png b/legacy/public/assets/img/Key/UrbosasFury.png deleted file mode 100644 index 050256c..0000000 Binary files a/legacy/public/assets/img/Key/UrbosasFury.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/UrbosasFuryDisabled.png b/legacy/public/assets/img/Key/UrbosasFuryDisabled.png deleted file mode 100644 index 9402a55..0000000 Binary files a/legacy/public/assets/img/Key/UrbosasFuryDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/UrbosasFuryPlus.png b/legacy/public/assets/img/Key/UrbosasFuryPlus.png deleted file mode 100644 index b7160b7..0000000 Binary files a/legacy/public/assets/img/Key/UrbosasFuryPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Key/UrbosasFuryPlusDisabled.png b/legacy/public/assets/img/Key/UrbosasFuryPlusDisabled.png deleted file mode 100644 index 9ab79d7..0000000 Binary files a/legacy/public/assets/img/Key/UrbosasFuryPlusDisabled.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Acorn.png b/legacy/public/assets/img/Material/Acorn.png deleted file mode 100644 index 74c1fc1..0000000 Binary files a/legacy/public/assets/img/Material/Acorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Amber.png b/legacy/public/assets/img/Material/Amber.png deleted file mode 100644 index 2eafba2..0000000 Binary files a/legacy/public/assets/img/Material/Amber.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/AncientCore.png b/legacy/public/assets/img/Material/AncientCore.png deleted file mode 100644 index 934253f..0000000 Binary files a/legacy/public/assets/img/Material/AncientCore.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/AncientGear.png b/legacy/public/assets/img/Material/AncientGear.png deleted file mode 100644 index 893370e..0000000 Binary files a/legacy/public/assets/img/Material/AncientGear.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/AncientScrew.png b/legacy/public/assets/img/Material/AncientScrew.png deleted file mode 100644 index 08d7f16..0000000 Binary files a/legacy/public/assets/img/Material/AncientScrew.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/AncientShaft.png b/legacy/public/assets/img/Material/AncientShaft.png deleted file mode 100644 index 867bfbb..0000000 Binary files a/legacy/public/assets/img/Material/AncientShaft.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/AncientSpring.png b/legacy/public/assets/img/Material/AncientSpring.png deleted file mode 100644 index c1f211d..0000000 Binary files a/legacy/public/assets/img/Material/AncientSpring.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Apple.png b/legacy/public/assets/img/Material/Apple.png deleted file mode 100644 index e6e9973..0000000 Binary files a/legacy/public/assets/img/Material/Apple.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Armoranth.png b/legacy/public/assets/img/Material/Armoranth.png deleted file mode 100644 index 564cb9c..0000000 Binary files a/legacy/public/assets/img/Material/Armoranth.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ArmoredCarp.png b/legacy/public/assets/img/Material/ArmoredCarp.png deleted file mode 100644 index 586fbf7..0000000 Binary files a/legacy/public/assets/img/Material/ArmoredCarp.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ArmoredPorgy.png b/legacy/public/assets/img/Material/ArmoredPorgy.png deleted file mode 100644 index b7cac60..0000000 Binary files a/legacy/public/assets/img/Material/ArmoredPorgy.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BigHeartyRadish.png b/legacy/public/assets/img/Material/BigHeartyRadish.png deleted file mode 100644 index 04e70de..0000000 Binary files a/legacy/public/assets/img/Material/BigHeartyRadish.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BigHeartyTruffle.png b/legacy/public/assets/img/Material/BigHeartyTruffle.png deleted file mode 100644 index 0526d5b..0000000 Binary files a/legacy/public/assets/img/Material/BigHeartyTruffle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BirdEgg.png b/legacy/public/assets/img/Material/BirdEgg.png deleted file mode 100644 index 8a4508f..0000000 Binary files a/legacy/public/assets/img/Material/BirdEgg.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BladedRhinoBeetle.png b/legacy/public/assets/img/Material/BladedRhinoBeetle.png deleted file mode 100644 index d947cd7..0000000 Binary files a/legacy/public/assets/img/Material/BladedRhinoBeetle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BlueNightshade.png b/legacy/public/assets/img/Material/BlueNightshade.png deleted file mode 100644 index 268812f..0000000 Binary files a/legacy/public/assets/img/Material/BlueNightshade.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BokoblinFang.png b/legacy/public/assets/img/Material/BokoblinFang.png deleted file mode 100644 index 2107711..0000000 Binary files a/legacy/public/assets/img/Material/BokoblinFang.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BokoblinGuts.png b/legacy/public/assets/img/Material/BokoblinGuts.png deleted file mode 100644 index 36d102a..0000000 Binary files a/legacy/public/assets/img/Material/BokoblinGuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BokoblinHorn.png b/legacy/public/assets/img/Material/BokoblinHorn.png deleted file mode 100644 index 5e8c85e..0000000 Binary files a/legacy/public/assets/img/Material/BokoblinHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/BrightEyedCrab.png b/legacy/public/assets/img/Material/BrightEyedCrab.png deleted file mode 100644 index e756ecf..0000000 Binary files a/legacy/public/assets/img/Material/BrightEyedCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/CaneSugar.png b/legacy/public/assets/img/Material/CaneSugar.png deleted file mode 100644 index b40339e..0000000 Binary files a/legacy/public/assets/img/Material/CaneSugar.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ChickalooTreeNut.png b/legacy/public/assets/img/Material/ChickalooTreeNut.png deleted file mode 100644 index 6cdb6be..0000000 Binary files a/legacy/public/assets/img/Material/ChickalooTreeNut.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ChillfinTrout.png b/legacy/public/assets/img/Material/ChillfinTrout.png deleted file mode 100644 index 803da56..0000000 Binary files a/legacy/public/assets/img/Material/ChillfinTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Chillshroom.png b/legacy/public/assets/img/Material/Chillshroom.png deleted file mode 100644 index 517e009..0000000 Binary files a/legacy/public/assets/img/Material/Chillshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ChuchuJelly.png b/legacy/public/assets/img/Material/ChuchuJelly.png deleted file mode 100644 index ae9940c..0000000 Binary files a/legacy/public/assets/img/Material/ChuchuJelly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ColdDarner.png b/legacy/public/assets/img/Material/ColdDarner.png deleted file mode 100644 index 412835b..0000000 Binary files a/legacy/public/assets/img/Material/ColdDarner.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/CoolSafflina.png b/legacy/public/assets/img/Material/CoolSafflina.png deleted file mode 100644 index 225faf5..0000000 Binary files a/legacy/public/assets/img/Material/CoolSafflina.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/CourserBeeHoney.png b/legacy/public/assets/img/Material/CourserBeeHoney.png deleted file mode 100644 index cde2c7e..0000000 Binary files a/legacy/public/assets/img/Material/CourserBeeHoney.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Diamond.png b/legacy/public/assets/img/Material/Diamond.png deleted file mode 100644 index bb3e125..0000000 Binary files a/legacy/public/assets/img/Material/Diamond.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/DinraalsClaw.png b/legacy/public/assets/img/Material/DinraalsClaw.png deleted file mode 100644 index bc950b2..0000000 Binary files a/legacy/public/assets/img/Material/DinraalsClaw.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/DinraalsScale.png b/legacy/public/assets/img/Material/DinraalsScale.png deleted file mode 100644 index 8f052cc..0000000 Binary files a/legacy/public/assets/img/Material/DinraalsScale.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ElectricDarner.png b/legacy/public/assets/img/Material/ElectricDarner.png deleted file mode 100644 index 76f67ff..0000000 Binary files a/legacy/public/assets/img/Material/ElectricDarner.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ElectricKeeseWing.png b/legacy/public/assets/img/Material/ElectricKeeseWing.png deleted file mode 100644 index f4d062a..0000000 Binary files a/legacy/public/assets/img/Material/ElectricKeeseWing.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ElectricSafflina.png b/legacy/public/assets/img/Material/ElectricSafflina.png deleted file mode 100644 index c386eae..0000000 Binary files a/legacy/public/assets/img/Material/ElectricSafflina.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/EnduraCarrot.png b/legacy/public/assets/img/Material/EnduraCarrot.png deleted file mode 100644 index 6e61753..0000000 Binary files a/legacy/public/assets/img/Material/EnduraCarrot.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/EnduraShroom.png b/legacy/public/assets/img/Material/EnduraShroom.png deleted file mode 100644 index 499e386..0000000 Binary files a/legacy/public/assets/img/Material/EnduraShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/EnergeticRhinoBeetle.png b/legacy/public/assets/img/Material/EnergeticRhinoBeetle.png deleted file mode 100644 index 4603e48..0000000 Binary files a/legacy/public/assets/img/Material/EnergeticRhinoBeetle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Fairy.png b/legacy/public/assets/img/Material/Fairy.png deleted file mode 100644 index b4ada1b..0000000 Binary files a/legacy/public/assets/img/Material/Fairy.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FaroshsClaw.png b/legacy/public/assets/img/Material/FaroshsClaw.png deleted file mode 100644 index 2f7c53a..0000000 Binary files a/legacy/public/assets/img/Material/FaroshsClaw.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FaroshsScale.png b/legacy/public/assets/img/Material/FaroshsScale.png deleted file mode 100644 index 32dd3e2..0000000 Binary files a/legacy/public/assets/img/Material/FaroshsScale.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FireKeeseWing.png b/legacy/public/assets/img/Material/FireKeeseWing.png deleted file mode 100644 index 1cd89a5..0000000 Binary files a/legacy/public/assets/img/Material/FireKeeseWing.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FireproofLizard.png b/legacy/public/assets/img/Material/FireproofLizard.png deleted file mode 100644 index 1f79467..0000000 Binary files a/legacy/public/assets/img/Material/FireproofLizard.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FleetLotusSeeds.png b/legacy/public/assets/img/Material/FleetLotusSeeds.png deleted file mode 100644 index 9816493..0000000 Binary files a/legacy/public/assets/img/Material/FleetLotusSeeds.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Flint.png b/legacy/public/assets/img/Material/Flint.png deleted file mode 100644 index 53903d3..0000000 Binary files a/legacy/public/assets/img/Material/Flint.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FortifiedPumpkin.png b/legacy/public/assets/img/Material/FortifiedPumpkin.png deleted file mode 100644 index dbace0a..0000000 Binary files a/legacy/public/assets/img/Material/FortifiedPumpkin.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/FreshMilk.png b/legacy/public/assets/img/Material/FreshMilk.png deleted file mode 100644 index 4804627..0000000 Binary files a/legacy/public/assets/img/Material/FreshMilk.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/GiantAncientCore.png b/legacy/public/assets/img/Material/GiantAncientCore.png deleted file mode 100644 index 8e1496d..0000000 Binary files a/legacy/public/assets/img/Material/GiantAncientCore.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/GoatButter.png b/legacy/public/assets/img/Material/GoatButter.png deleted file mode 100644 index 72a8da1..0000000 Binary files a/legacy/public/assets/img/Material/GoatButter.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/GoronSpice.png b/legacy/public/assets/img/Material/GoronSpice.png deleted file mode 100644 index 291caae..0000000 Binary files a/legacy/public/assets/img/Material/GoronSpice.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyBass.png b/legacy/public/assets/img/Material/HeartyBass.png deleted file mode 100644 index 7e1cbe4..0000000 Binary files a/legacy/public/assets/img/Material/HeartyBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyBlueshellSnail.png b/legacy/public/assets/img/Material/HeartyBlueshellSnail.png deleted file mode 100644 index a710bda..0000000 Binary files a/legacy/public/assets/img/Material/HeartyBlueshellSnail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyDurian.png b/legacy/public/assets/img/Material/HeartyDurian.png deleted file mode 100644 index ccd5f2f..0000000 Binary files a/legacy/public/assets/img/Material/HeartyDurian.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyLizard.png b/legacy/public/assets/img/Material/HeartyLizard.png deleted file mode 100644 index f5513c6..0000000 Binary files a/legacy/public/assets/img/Material/HeartyLizard.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyRadish.png b/legacy/public/assets/img/Material/HeartyRadish.png deleted file mode 100644 index 254e45d..0000000 Binary files a/legacy/public/assets/img/Material/HeartyRadish.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartySalmon.png b/legacy/public/assets/img/Material/HeartySalmon.png deleted file mode 100644 index 58f5bcb..0000000 Binary files a/legacy/public/assets/img/Material/HeartySalmon.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HeartyTruffle.png b/legacy/public/assets/img/Material/HeartyTruffle.png deleted file mode 100644 index be74661..0000000 Binary files a/legacy/public/assets/img/Material/HeartyTruffle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HightailLizard.png b/legacy/public/assets/img/Material/HightailLizard.png deleted file mode 100644 index ae17b3f..0000000 Binary files a/legacy/public/assets/img/Material/HightailLizard.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HinoxGuts.png b/legacy/public/assets/img/Material/HinoxGuts.png deleted file mode 100644 index 3300c0f..0000000 Binary files a/legacy/public/assets/img/Material/HinoxGuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HinoxToenail.png b/legacy/public/assets/img/Material/HinoxToenail.png deleted file mode 100644 index df4b533..0000000 Binary files a/legacy/public/assets/img/Material/HinoxToenail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HinoxTooth.png b/legacy/public/assets/img/Material/HinoxTooth.png deleted file mode 100644 index 51a0055..0000000 Binary files a/legacy/public/assets/img/Material/HinoxTooth.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HotFootedFrog.png b/legacy/public/assets/img/Material/HotFootedFrog.png deleted file mode 100644 index 8da91ea..0000000 Binary files a/legacy/public/assets/img/Material/HotFootedFrog.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Hydromelon.png b/legacy/public/assets/img/Material/Hydromelon.png deleted file mode 100644 index 7d2699b..0000000 Binary files a/legacy/public/assets/img/Material/Hydromelon.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HylianRice.png b/legacy/public/assets/img/Material/HylianRice.png deleted file mode 100644 index a905059..0000000 Binary files a/legacy/public/assets/img/Material/HylianRice.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HylianShroom.png b/legacy/public/assets/img/Material/HylianShroom.png deleted file mode 100644 index 979c3b4..0000000 Binary files a/legacy/public/assets/img/Material/HylianShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HyruleBass.png b/legacy/public/assets/img/Material/HyruleBass.png deleted file mode 100644 index 6775618..0000000 Binary files a/legacy/public/assets/img/Material/HyruleBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/HyruleHerb.png b/legacy/public/assets/img/Material/HyruleHerb.png deleted file mode 100644 index bcfd018..0000000 Binary files a/legacy/public/assets/img/Material/HyruleHerb.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/IceKeeseWing.png b/legacy/public/assets/img/Material/IceKeeseWing.png deleted file mode 100644 index de86620..0000000 Binary files a/legacy/public/assets/img/Material/IceKeeseWing.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/IcyLizalfosTail.png b/legacy/public/assets/img/Material/IcyLizalfosTail.png deleted file mode 100644 index 30e97d2..0000000 Binary files a/legacy/public/assets/img/Material/IcyLizalfosTail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/IronshellCrab.png b/legacy/public/assets/img/Material/IronshellCrab.png deleted file mode 100644 index 398983b..0000000 Binary files a/legacy/public/assets/img/Material/IronshellCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Ironshroom.png b/legacy/public/assets/img/Material/Ironshroom.png deleted file mode 100644 index cc3cec8..0000000 Binary files a/legacy/public/assets/img/Material/Ironshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/KeeseEyeball.png b/legacy/public/assets/img/Material/KeeseEyeball.png deleted file mode 100644 index 1cff751..0000000 Binary files a/legacy/public/assets/img/Material/KeeseEyeball.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/KeeseWing.png b/legacy/public/assets/img/Material/KeeseWing.png deleted file mode 100644 index 9f031d7..0000000 Binary files a/legacy/public/assets/img/Material/KeeseWing.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LizalfosHorn.png b/legacy/public/assets/img/Material/LizalfosHorn.png deleted file mode 100644 index da8dbaf..0000000 Binary files a/legacy/public/assets/img/Material/LizalfosHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LizalfosTail.png b/legacy/public/assets/img/Material/LizalfosTail.png deleted file mode 100644 index 0dccf6a..0000000 Binary files a/legacy/public/assets/img/Material/LizalfosTail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LizalfosTalon.png b/legacy/public/assets/img/Material/LizalfosTalon.png deleted file mode 100644 index a6c7f6f..0000000 Binary files a/legacy/public/assets/img/Material/LizalfosTalon.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LuminousStone.png b/legacy/public/assets/img/Material/LuminousStone.png deleted file mode 100644 index f173c3d..0000000 Binary files a/legacy/public/assets/img/Material/LuminousStone.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LynelGuts.png b/legacy/public/assets/img/Material/LynelGuts.png deleted file mode 100644 index 13f1fb4..0000000 Binary files a/legacy/public/assets/img/Material/LynelGuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LynelHoof.png b/legacy/public/assets/img/Material/LynelHoof.png deleted file mode 100644 index 0201907..0000000 Binary files a/legacy/public/assets/img/Material/LynelHoof.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/LynelHorn.png b/legacy/public/assets/img/Material/LynelHorn.png deleted file mode 100644 index bd57d3e..0000000 Binary files a/legacy/public/assets/img/Material/LynelHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MightyBananas.png b/legacy/public/assets/img/Material/MightyBananas.png deleted file mode 100644 index ab57ee3..0000000 Binary files a/legacy/public/assets/img/Material/MightyBananas.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MightyCarp.png b/legacy/public/assets/img/Material/MightyCarp.png deleted file mode 100644 index a6b07b6..0000000 Binary files a/legacy/public/assets/img/Material/MightyCarp.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MightyPorgy.png b/legacy/public/assets/img/Material/MightyPorgy.png deleted file mode 100644 index 08c822e..0000000 Binary files a/legacy/public/assets/img/Material/MightyPorgy.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MightyThistle.png b/legacy/public/assets/img/Material/MightyThistle.png deleted file mode 100644 index 3235411..0000000 Binary files a/legacy/public/assets/img/Material/MightyThistle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MoblinFang.png b/legacy/public/assets/img/Material/MoblinFang.png deleted file mode 100644 index f9ca78a..0000000 Binary files a/legacy/public/assets/img/Material/MoblinFang.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MoblinGuts.png b/legacy/public/assets/img/Material/MoblinGuts.png deleted file mode 100644 index c271f26..0000000 Binary files a/legacy/public/assets/img/Material/MoblinGuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MoblinHorn.png b/legacy/public/assets/img/Material/MoblinHorn.png deleted file mode 100644 index 0fcb4cc..0000000 Binary files a/legacy/public/assets/img/Material/MoblinHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MoldugaFin.png b/legacy/public/assets/img/Material/MoldugaFin.png deleted file mode 100644 index 6b44fb0..0000000 Binary files a/legacy/public/assets/img/Material/MoldugaFin.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MoldugaGuts.png b/legacy/public/assets/img/Material/MoldugaGuts.png deleted file mode 100644 index 6685f21..0000000 Binary files a/legacy/public/assets/img/Material/MoldugaGuts.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/MonsterExtract.png b/legacy/public/assets/img/Material/MonsterExtract.png deleted file mode 100644 index 3625478..0000000 Binary files a/legacy/public/assets/img/Material/MonsterExtract.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/NaydrasClaw.png b/legacy/public/assets/img/Material/NaydrasClaw.png deleted file mode 100644 index fb9a595..0000000 Binary files a/legacy/public/assets/img/Material/NaydrasClaw.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/NaydrasScale.png b/legacy/public/assets/img/Material/NaydrasScale.png deleted file mode 100644 index 3f87f52..0000000 Binary files a/legacy/public/assets/img/Material/NaydrasScale.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/OctoBalloon.png b/legacy/public/assets/img/Material/OctoBalloon.png deleted file mode 100644 index c9c885a..0000000 Binary files a/legacy/public/assets/img/Material/OctoBalloon.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/OctorokEyeball.png b/legacy/public/assets/img/Material/OctorokEyeball.png deleted file mode 100644 index f7c5ce2..0000000 Binary files a/legacy/public/assets/img/Material/OctorokEyeball.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/OctorokTentacle.png b/legacy/public/assets/img/Material/OctorokTentacle.png deleted file mode 100644 index d9d3697..0000000 Binary files a/legacy/public/assets/img/Material/OctorokTentacle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Opal.png b/legacy/public/assets/img/Material/Opal.png deleted file mode 100644 index e0bf890..0000000 Binary files a/legacy/public/assets/img/Material/Opal.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/PalmFruit.png b/legacy/public/assets/img/Material/PalmFruit.png deleted file mode 100644 index 228f6e9..0000000 Binary files a/legacy/public/assets/img/Material/PalmFruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawBirdDrumstick.png b/legacy/public/assets/img/Material/RawBirdDrumstick.png deleted file mode 100644 index c528926..0000000 Binary files a/legacy/public/assets/img/Material/RawBirdDrumstick.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawBirdThigh.png b/legacy/public/assets/img/Material/RawBirdThigh.png deleted file mode 100644 index 920a91f..0000000 Binary files a/legacy/public/assets/img/Material/RawBirdThigh.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawGourmetMeat.png b/legacy/public/assets/img/Material/RawGourmetMeat.png deleted file mode 100644 index 3e86e1d..0000000 Binary files a/legacy/public/assets/img/Material/RawGourmetMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawMeat.png b/legacy/public/assets/img/Material/RawMeat.png deleted file mode 100644 index d547266..0000000 Binary files a/legacy/public/assets/img/Material/RawMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawPrimeMeat.png b/legacy/public/assets/img/Material/RawPrimeMeat.png deleted file mode 100644 index a9f8fbf..0000000 Binary files a/legacy/public/assets/img/Material/RawPrimeMeat.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RawWholeBird.png b/legacy/public/assets/img/Material/RawWholeBird.png deleted file mode 100644 index b1ada3f..0000000 Binary files a/legacy/public/assets/img/Material/RawWholeBird.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RazorclawCrab.png b/legacy/public/assets/img/Material/RazorclawCrab.png deleted file mode 100644 index a7c757d..0000000 Binary files a/legacy/public/assets/img/Material/RazorclawCrab.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Razorshroom.png b/legacy/public/assets/img/Material/Razorshroom.png deleted file mode 100644 index bdf9d4a..0000000 Binary files a/legacy/public/assets/img/Material/Razorshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RedChuchuJelly.png b/legacy/public/assets/img/Material/RedChuchuJelly.png deleted file mode 100644 index e03d676..0000000 Binary files a/legacy/public/assets/img/Material/RedChuchuJelly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RedLizalfosTail.png b/legacy/public/assets/img/Material/RedLizalfosTail.png deleted file mode 100644 index 3299018..0000000 Binary files a/legacy/public/assets/img/Material/RedLizalfosTail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RestlessCricket.png b/legacy/public/assets/img/Material/RestlessCricket.png deleted file mode 100644 index b856998..0000000 Binary files a/legacy/public/assets/img/Material/RestlessCricket.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RockSalt.png b/legacy/public/assets/img/Material/RockSalt.png deleted file mode 100644 index f357f00..0000000 Binary files a/legacy/public/assets/img/Material/RockSalt.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Ruby.png b/legacy/public/assets/img/Material/Ruby.png deleted file mode 100644 index 9f47d17..0000000 Binary files a/legacy/public/assets/img/Material/Ruby.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/RuggedRhinoBeetle.png b/legacy/public/assets/img/Material/RuggedRhinoBeetle.png deleted file mode 100644 index 2c7d600..0000000 Binary files a/legacy/public/assets/img/Material/RuggedRhinoBeetle.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Rushroom.png b/legacy/public/assets/img/Material/Rushroom.png deleted file mode 100644 index a73e6fa..0000000 Binary files a/legacy/public/assets/img/Material/Rushroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SankeCarp.png b/legacy/public/assets/img/Material/SankeCarp.png deleted file mode 100644 index 7d2fe86..0000000 Binary files a/legacy/public/assets/img/Material/SankeCarp.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Sapphire.png b/legacy/public/assets/img/Material/Sapphire.png deleted file mode 100644 index cbba302..0000000 Binary files a/legacy/public/assets/img/Material/Sapphire.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfDinraalsFang.png b/legacy/public/assets/img/Material/ShardOfDinraalsFang.png deleted file mode 100644 index a4baf5d..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfDinraalsFang.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfDinraalsHorn.png b/legacy/public/assets/img/Material/ShardOfDinraalsHorn.png deleted file mode 100644 index c4dadac..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfDinraalsHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfFaroshsFang.png b/legacy/public/assets/img/Material/ShardOfFaroshsFang.png deleted file mode 100644 index 2e341f5..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfFaroshsFang.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfFaroshsHorn.png b/legacy/public/assets/img/Material/ShardOfFaroshsHorn.png deleted file mode 100644 index cb8ce9a..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfFaroshsHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfNaydrasFang.png b/legacy/public/assets/img/Material/ShardOfNaydrasFang.png deleted file mode 100644 index 082b6ea..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfNaydrasFang.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ShardOfNaydrasHorn.png b/legacy/public/assets/img/Material/ShardOfNaydrasHorn.png deleted file mode 100644 index 59e61c3..0000000 Binary files a/legacy/public/assets/img/Material/ShardOfNaydrasHorn.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SilentPrincess.png b/legacy/public/assets/img/Material/SilentPrincess.png deleted file mode 100644 index 61ae3f8..0000000 Binary files a/legacy/public/assets/img/Material/SilentPrincess.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SilentShroom.png b/legacy/public/assets/img/Material/SilentShroom.png deleted file mode 100644 index 2bb7cc3..0000000 Binary files a/legacy/public/assets/img/Material/SilentShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SizzlefinTrout.png b/legacy/public/assets/img/Material/SizzlefinTrout.png deleted file mode 100644 index 949654f..0000000 Binary files a/legacy/public/assets/img/Material/SizzlefinTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SmotherwingButterfly.png b/legacy/public/assets/img/Material/SmotherwingButterfly.png deleted file mode 100644 index d22b45f..0000000 Binary files a/legacy/public/assets/img/Material/SmotherwingButterfly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SneakyRiverSnail.png b/legacy/public/assets/img/Material/SneakyRiverSnail.png deleted file mode 100644 index fde9200..0000000 Binary files a/legacy/public/assets/img/Material/SneakyRiverSnail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SpicyPepper.png b/legacy/public/assets/img/Material/SpicyPepper.png deleted file mode 100644 index e8b5d41..0000000 Binary files a/legacy/public/assets/img/Material/SpicyPepper.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/StamellaShroom.png b/legacy/public/assets/img/Material/StamellaShroom.png deleted file mode 100644 index a0d9811..0000000 Binary files a/legacy/public/assets/img/Material/StamellaShroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/StaminokaBass.png b/legacy/public/assets/img/Material/StaminokaBass.png deleted file mode 100644 index ad97a38..0000000 Binary files a/legacy/public/assets/img/Material/StaminokaBass.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/StarFragment.png b/legacy/public/assets/img/Material/StarFragment.png deleted file mode 100644 index be4ec7c..0000000 Binary files a/legacy/public/assets/img/Material/StarFragment.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/StealthfinTrout.png b/legacy/public/assets/img/Material/StealthfinTrout.png deleted file mode 100644 index c09cd05..0000000 Binary files a/legacy/public/assets/img/Material/StealthfinTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SummerwingButterfly.png b/legacy/public/assets/img/Material/SummerwingButterfly.png deleted file mode 100644 index 7885d60..0000000 Binary files a/legacy/public/assets/img/Material/SummerwingButterfly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SunsetFirefly.png b/legacy/public/assets/img/Material/SunsetFirefly.png deleted file mode 100644 index 705cd39..0000000 Binary files a/legacy/public/assets/img/Material/SunsetFirefly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Sunshroom.png b/legacy/public/assets/img/Material/Sunshroom.png deleted file mode 100644 index 282a456..0000000 Binary files a/legacy/public/assets/img/Material/Sunshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SwiftCarrot.png b/legacy/public/assets/img/Material/SwiftCarrot.png deleted file mode 100644 index 65b6f10..0000000 Binary files a/legacy/public/assets/img/Material/SwiftCarrot.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/SwiftViolet.png b/legacy/public/assets/img/Material/SwiftViolet.png deleted file mode 100644 index ec8a297..0000000 Binary files a/legacy/public/assets/img/Material/SwiftViolet.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/TabanthaWheat.png b/legacy/public/assets/img/Material/TabanthaWheat.png deleted file mode 100644 index 8e57359..0000000 Binary files a/legacy/public/assets/img/Material/TabanthaWheat.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/ThunderwingButterfly.png b/legacy/public/assets/img/Material/ThunderwingButterfly.png deleted file mode 100644 index 8121300..0000000 Binary files a/legacy/public/assets/img/Material/ThunderwingButterfly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/TirelessFrog.png b/legacy/public/assets/img/Material/TirelessFrog.png deleted file mode 100644 index 6409c12..0000000 Binary files a/legacy/public/assets/img/Material/TirelessFrog.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Topaz.png b/legacy/public/assets/img/Material/Topaz.png deleted file mode 100644 index 2ba8472..0000000 Binary files a/legacy/public/assets/img/Material/Topaz.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/VoltfinTrout.png b/legacy/public/assets/img/Material/VoltfinTrout.png deleted file mode 100644 index f30ccf2..0000000 Binary files a/legacy/public/assets/img/Material/VoltfinTrout.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Voltfruit.png b/legacy/public/assets/img/Material/Voltfruit.png deleted file mode 100644 index e824ce6..0000000 Binary files a/legacy/public/assets/img/Material/Voltfruit.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/WarmDarner.png b/legacy/public/assets/img/Material/WarmDarner.png deleted file mode 100644 index 2588263..0000000 Binary files a/legacy/public/assets/img/Material/WarmDarner.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/WarmSafflina.png b/legacy/public/assets/img/Material/WarmSafflina.png deleted file mode 100644 index 77722db..0000000 Binary files a/legacy/public/assets/img/Material/WarmSafflina.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/WhiteChuchuJelly.png b/legacy/public/assets/img/Material/WhiteChuchuJelly.png deleted file mode 100644 index 41e1c04..0000000 Binary files a/legacy/public/assets/img/Material/WhiteChuchuJelly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Wildberry.png b/legacy/public/assets/img/Material/Wildberry.png deleted file mode 100644 index 2d20ec1..0000000 Binary files a/legacy/public/assets/img/Material/Wildberry.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/WinterwingButterfly.png b/legacy/public/assets/img/Material/WinterwingButterfly.png deleted file mode 100644 index ac08f92..0000000 Binary files a/legacy/public/assets/img/Material/WinterwingButterfly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Wood.png b/legacy/public/assets/img/Material/Wood.png deleted file mode 100644 index b520c1e..0000000 Binary files a/legacy/public/assets/img/Material/Wood.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/YellowChuchuJelly.png b/legacy/public/assets/img/Material/YellowChuchuJelly.png deleted file mode 100644 index 0e56afd..0000000 Binary files a/legacy/public/assets/img/Material/YellowChuchuJelly.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/YellowLizalfosTail.png b/legacy/public/assets/img/Material/YellowLizalfosTail.png deleted file mode 100644 index 9582213..0000000 Binary files a/legacy/public/assets/img/Material/YellowLizalfosTail.png and /dev/null differ diff --git a/legacy/public/assets/img/Material/Zapshroom.png b/legacy/public/assets/img/Material/Zapshroom.png deleted file mode 100644 index bbaad3a..0000000 Binary files a/legacy/public/assets/img/Material/Zapshroom.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/BowAttackUp.png b/legacy/public/assets/img/Modifiers/BowAttackUp.png deleted file mode 100644 index fba59a1..0000000 Binary files a/legacy/public/assets/img/Modifiers/BowAttackUp.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/BowAttackUpYellow.png b/legacy/public/assets/img/Modifiers/BowAttackUpYellow.png deleted file mode 100644 index 0236b11..0000000 Binary files a/legacy/public/assets/img/Modifiers/BowAttackUpYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookChilly.png b/legacy/public/assets/img/Modifiers/CookChilly.png deleted file mode 100644 index d513cb1..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookChilly.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookElectro.png b/legacy/public/assets/img/Modifiers/CookElectro.png deleted file mode 100644 index adbe8f8..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookElectro.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookEnduring.png b/legacy/public/assets/img/Modifiers/CookEnduring.png deleted file mode 100644 index eb7f522..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookEnduring.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookEnergizing.png b/legacy/public/assets/img/Modifiers/CookEnergizing.png deleted file mode 100644 index 0d0b336..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookEnergizing.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookFireproof.png b/legacy/public/assets/img/Modifiers/CookFireproof.png deleted file mode 100644 index 3e92a3f..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookFireproof.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookHasty.png b/legacy/public/assets/img/Modifiers/CookHasty.png deleted file mode 100644 index 8638ea4..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookHasty.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookHearty.png b/legacy/public/assets/img/Modifiers/CookHearty.png deleted file mode 100644 index e9187b0..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookHearty.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookMighty.png b/legacy/public/assets/img/Modifiers/CookMighty.png deleted file mode 100644 index 885db62..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookMighty.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookSneaky.png b/legacy/public/assets/img/Modifiers/CookSneaky.png deleted file mode 100644 index 073f63c..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookSneaky.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookSpicy.png b/legacy/public/assets/img/Modifiers/CookSpicy.png deleted file mode 100644 index 582d735..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookSpicy.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CookTough.png b/legacy/public/assets/img/Modifiers/CookTough.png deleted file mode 100644 index e402a63..0000000 Binary files a/legacy/public/assets/img/Modifiers/CookTough.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CriticalHit.png b/legacy/public/assets/img/Modifiers/CriticalHit.png deleted file mode 100644 index 22d1be7..0000000 Binary files a/legacy/public/assets/img/Modifiers/CriticalHit.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/CriticalHitYellow.png b/legacy/public/assets/img/Modifiers/CriticalHitYellow.png deleted file mode 100644 index c153f8d..0000000 Binary files a/legacy/public/assets/img/Modifiers/CriticalHitYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/DurabilityUp.png b/legacy/public/assets/img/Modifiers/DurabilityUp.png deleted file mode 100644 index 231cedb..0000000 Binary files a/legacy/public/assets/img/Modifiers/DurabilityUp.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/DurabilityUpYellow.png b/legacy/public/assets/img/Modifiers/DurabilityUpYellow.png deleted file mode 100644 index 8e2d869..0000000 Binary files a/legacy/public/assets/img/Modifiers/DurabilityUpYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/GuardUp.png b/legacy/public/assets/img/Modifiers/GuardUp.png deleted file mode 100644 index b588f96..0000000 Binary files a/legacy/public/assets/img/Modifiers/GuardUp.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/GuardUpYellow.png b/legacy/public/assets/img/Modifiers/GuardUpYellow.png deleted file mode 100644 index 2234e28..0000000 Binary files a/legacy/public/assets/img/Modifiers/GuardUpYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/LongThrow.png b/legacy/public/assets/img/Modifiers/LongThrow.png deleted file mode 100644 index 1f70382..0000000 Binary files a/legacy/public/assets/img/Modifiers/LongThrow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/LongThrowYellow.png b/legacy/public/assets/img/Modifiers/LongThrowYellow.png deleted file mode 100644 index c0c3b50..0000000 Binary files a/legacy/public/assets/img/Modifiers/LongThrowYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/Multishot3.png b/legacy/public/assets/img/Modifiers/Multishot3.png deleted file mode 100644 index fe25956..0000000 Binary files a/legacy/public/assets/img/Modifiers/Multishot3.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/Multishot5.png b/legacy/public/assets/img/Modifiers/Multishot5.png deleted file mode 100644 index ecc2631..0000000 Binary files a/legacy/public/assets/img/Modifiers/Multishot5.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/MultishotX.png b/legacy/public/assets/img/Modifiers/MultishotX.png deleted file mode 100644 index 86308c9..0000000 Binary files a/legacy/public/assets/img/Modifiers/MultishotX.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/QuickShot.png b/legacy/public/assets/img/Modifiers/QuickShot.png deleted file mode 100644 index 35474a9..0000000 Binary files a/legacy/public/assets/img/Modifiers/QuickShot.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/QuickShotYellow.png b/legacy/public/assets/img/Modifiers/QuickShotYellow.png deleted file mode 100644 index 83b6599..0000000 Binary files a/legacy/public/assets/img/Modifiers/QuickShotYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/SurfMaster.png b/legacy/public/assets/img/Modifiers/SurfMaster.png deleted file mode 100644 index 2e46f06..0000000 Binary files a/legacy/public/assets/img/Modifiers/SurfMaster.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/SurfMasterYellow.png b/legacy/public/assets/img/Modifiers/SurfMasterYellow.png deleted file mode 100644 index 98501d4..0000000 Binary files a/legacy/public/assets/img/Modifiers/SurfMasterYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/WeaponAttackUp.png b/legacy/public/assets/img/Modifiers/WeaponAttackUp.png deleted file mode 100644 index 885db62..0000000 Binary files a/legacy/public/assets/img/Modifiers/WeaponAttackUp.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/WeaponAttackUpYellow.png b/legacy/public/assets/img/Modifiers/WeaponAttackUpYellow.png deleted file mode 100644 index bf2815c..0000000 Binary files a/legacy/public/assets/img/Modifiers/WeaponAttackUpYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/Zoom.png b/legacy/public/assets/img/Modifiers/Zoom.png deleted file mode 100644 index a6fab98..0000000 Binary files a/legacy/public/assets/img/Modifiers/Zoom.png and /dev/null differ diff --git a/legacy/public/assets/img/Modifiers/ZoomYellow.png b/legacy/public/assets/img/Modifiers/ZoomYellow.png deleted file mode 100644 index 4eafe1d..0000000 Binary files a/legacy/public/assets/img/Modifiers/ZoomYellow.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/AncientShield.png b/legacy/public/assets/img/Shield/AncientShield.png deleted file mode 100644 index f20c2e6..0000000 Binary files a/legacy/public/assets/img/Shield/AncientShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/BokoShield.png b/legacy/public/assets/img/Shield/BokoShield.png deleted file mode 100644 index 61bf94e..0000000 Binary files a/legacy/public/assets/img/Shield/BokoShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/Daybreaker.png b/legacy/public/assets/img/Shield/Daybreaker.png deleted file mode 100644 index 15a1224..0000000 Binary files a/legacy/public/assets/img/Shield/Daybreaker.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/DragonboneBokoShield.png b/legacy/public/assets/img/Shield/DragonboneBokoShield.png deleted file mode 100644 index 5f5d4cc..0000000 Binary files a/legacy/public/assets/img/Shield/DragonboneBokoShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/EmblazonedShield.png b/legacy/public/assets/img/Shield/EmblazonedShield.png deleted file mode 100644 index 8bf1013..0000000 Binary files a/legacy/public/assets/img/Shield/EmblazonedShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/FishermansShield.png b/legacy/public/assets/img/Shield/FishermansShield.png deleted file mode 100644 index 437e8eb..0000000 Binary files a/legacy/public/assets/img/Shield/FishermansShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/ForestDwellersShield.png b/legacy/public/assets/img/Shield/ForestDwellersShield.png deleted file mode 100644 index fbe1605..0000000 Binary files a/legacy/public/assets/img/Shield/ForestDwellersShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/GerudoShield.png b/legacy/public/assets/img/Shield/GerudoShield.png deleted file mode 100644 index 18f9258..0000000 Binary files a/legacy/public/assets/img/Shield/GerudoShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/GuardianShield.png b/legacy/public/assets/img/Shield/GuardianShield.png deleted file mode 100644 index b9c7eb2..0000000 Binary files a/legacy/public/assets/img/Shield/GuardianShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/GuardianShieldPlus.png b/legacy/public/assets/img/Shield/GuardianShieldPlus.png deleted file mode 100644 index 6f24b7b..0000000 Binary files a/legacy/public/assets/img/Shield/GuardianShieldPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/GuardianShieldPlusPlus.png b/legacy/public/assets/img/Shield/GuardianShieldPlusPlus.png deleted file mode 100644 index f1aeb2c..0000000 Binary files a/legacy/public/assets/img/Shield/GuardianShieldPlusPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/HerosShield.png b/legacy/public/assets/img/Shield/HerosShield.png deleted file mode 100644 index a96c559..0000000 Binary files a/legacy/public/assets/img/Shield/HerosShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/HuntersShield.png b/legacy/public/assets/img/Shield/HuntersShield.png deleted file mode 100644 index 0c9e153..0000000 Binary files a/legacy/public/assets/img/Shield/HuntersShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/HylianShield.png b/legacy/public/assets/img/Shield/HylianShield.png deleted file mode 100644 index 854ddcc..0000000 Binary files a/legacy/public/assets/img/Shield/HylianShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/KiteShield.png b/legacy/public/assets/img/Shield/KiteShield.png deleted file mode 100644 index df2017e..0000000 Binary files a/legacy/public/assets/img/Shield/KiteShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/KnightsShield.png b/legacy/public/assets/img/Shield/KnightsShield.png deleted file mode 100644 index 5f6b6da..0000000 Binary files a/legacy/public/assets/img/Shield/KnightsShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/LizalShield.png b/legacy/public/assets/img/Shield/LizalShield.png deleted file mode 100644 index 8054384..0000000 Binary files a/legacy/public/assets/img/Shield/LizalShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/LynelShield.png b/legacy/public/assets/img/Shield/LynelShield.png deleted file mode 100644 index 2aa0f3f..0000000 Binary files a/legacy/public/assets/img/Shield/LynelShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/MightyLynelShield.png b/legacy/public/assets/img/Shield/MightyLynelShield.png deleted file mode 100644 index 2f9ffb0..0000000 Binary files a/legacy/public/assets/img/Shield/MightyLynelShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/PotLid.png b/legacy/public/assets/img/Shield/PotLid.png deleted file mode 100644 index 7522bfa..0000000 Binary files a/legacy/public/assets/img/Shield/PotLid.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/RadiantShield.png b/legacy/public/assets/img/Shield/RadiantShield.png deleted file mode 100644 index 68af939..0000000 Binary files a/legacy/public/assets/img/Shield/RadiantShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/ReinforcedLizalShield.png b/legacy/public/assets/img/Shield/ReinforcedLizalShield.png deleted file mode 100644 index 9b7af5c..0000000 Binary files a/legacy/public/assets/img/Shield/ReinforcedLizalShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/RoyalGuardsShield.png b/legacy/public/assets/img/Shield/RoyalGuardsShield.png deleted file mode 100644 index 7510f1d..0000000 Binary files a/legacy/public/assets/img/Shield/RoyalGuardsShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/RoyalShield.png b/legacy/public/assets/img/Shield/RoyalShield.png deleted file mode 100644 index 963db4d..0000000 Binary files a/legacy/public/assets/img/Shield/RoyalShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/RustyShield.png b/legacy/public/assets/img/Shield/RustyShield.png deleted file mode 100644 index d7e841a..0000000 Binary files a/legacy/public/assets/img/Shield/RustyShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/SavageLynelShield.png b/legacy/public/assets/img/Shield/SavageLynelShield.png deleted file mode 100644 index 69c562a..0000000 Binary files a/legacy/public/assets/img/Shield/SavageLynelShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/Shield.png b/legacy/public/assets/img/Shield/Shield.png deleted file mode 100644 index 59bcc7a..0000000 Binary files a/legacy/public/assets/img/Shield/Shield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/ShieldOfTheMindsEye.png b/legacy/public/assets/img/Shield/ShieldOfTheMindsEye.png deleted file mode 100644 index 066ce68..0000000 Binary files a/legacy/public/assets/img/Shield/ShieldOfTheMindsEye.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/SilverShield.png b/legacy/public/assets/img/Shield/SilverShield.png deleted file mode 100644 index a1d8e16..0000000 Binary files a/legacy/public/assets/img/Shield/SilverShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/SoldiersShield.png b/legacy/public/assets/img/Shield/SoldiersShield.png deleted file mode 100644 index 6c35f33..0000000 Binary files a/legacy/public/assets/img/Shield/SoldiersShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/SpikedBokoShield.png b/legacy/public/assets/img/Shield/SpikedBokoShield.png deleted file mode 100644 index 128dcca..0000000 Binary files a/legacy/public/assets/img/Shield/SpikedBokoShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/SteelLizalShield.png b/legacy/public/assets/img/Shield/SteelLizalShield.png deleted file mode 100644 index 39fb36c..0000000 Binary files a/legacy/public/assets/img/Shield/SteelLizalShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/TravelersShield.png b/legacy/public/assets/img/Shield/TravelersShield.png deleted file mode 100644 index 93ad6cd..0000000 Binary files a/legacy/public/assets/img/Shield/TravelersShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Shield/WoodenShield.png b/legacy/public/assets/img/Shield/WoodenShield.png deleted file mode 100644 index 593131e..0000000 Binary files a/legacy/public/assets/img/Shield/WoodenShield.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientBattleAxe.png b/legacy/public/assets/img/Weapon/AncientBattleAxe.png deleted file mode 100644 index f9cf27f..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientBattleAxe.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientBattleAxePlus.png b/legacy/public/assets/img/Weapon/AncientBattleAxePlus.png deleted file mode 100644 index f8cb3f6..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientBattleAxePlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientBattleAxePlusPlus.png b/legacy/public/assets/img/Weapon/AncientBattleAxePlusPlus.png deleted file mode 100644 index 6dc89b2..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientBattleAxePlusPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientBladesaw.png b/legacy/public/assets/img/Weapon/AncientBladesaw.png deleted file mode 100644 index e1362f9..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientBladesaw.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientShortSword.png b/legacy/public/assets/img/Weapon/AncientShortSword.png deleted file mode 100644 index c7b8b75..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientShortSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/AncientSpear.png b/legacy/public/assets/img/Weapon/AncientSpear.png deleted file mode 100644 index 2c979e6..0000000 Binary files a/legacy/public/assets/img/Weapon/AncientSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BiggoronsSword.png b/legacy/public/assets/img/Weapon/BiggoronsSword.png deleted file mode 100644 index 566bb91..0000000 Binary files a/legacy/public/assets/img/Weapon/BiggoronsSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BlizzardRod.png b/legacy/public/assets/img/Weapon/BlizzardRod.png deleted file mode 100644 index e09d056..0000000 Binary files a/legacy/public/assets/img/Weapon/BlizzardRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BoatOar.png b/legacy/public/assets/img/Weapon/BoatOar.png deleted file mode 100644 index e190184..0000000 Binary files a/legacy/public/assets/img/Weapon/BoatOar.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BokoBat.png b/legacy/public/assets/img/Weapon/BokoBat.png deleted file mode 100644 index 8f56045..0000000 Binary files a/legacy/public/assets/img/Weapon/BokoBat.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BokoClub.png b/legacy/public/assets/img/Weapon/BokoClub.png deleted file mode 100644 index 94ec8fc..0000000 Binary files a/legacy/public/assets/img/Weapon/BokoClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BokoSpear.png b/legacy/public/assets/img/Weapon/BokoSpear.png deleted file mode 100644 index e88c308..0000000 Binary files a/legacy/public/assets/img/Weapon/BokoSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BokoblinArm.png b/legacy/public/assets/img/Weapon/BokoblinArm.png deleted file mode 100644 index db5c541..0000000 Binary files a/legacy/public/assets/img/Weapon/BokoblinArm.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Boomerang.png b/legacy/public/assets/img/Weapon/Boomerang.png deleted file mode 100644 index 2b832ce..0000000 Binary files a/legacy/public/assets/img/Weapon/Boomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/BoulderBreaker.png b/legacy/public/assets/img/Weapon/BoulderBreaker.png deleted file mode 100644 index 77dd5c5..0000000 Binary files a/legacy/public/assets/img/Weapon/BoulderBreaker.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/CeremonialTrident.png b/legacy/public/assets/img/Weapon/CeremonialTrident.png deleted file mode 100644 index c45f117..0000000 Binary files a/legacy/public/assets/img/Weapon/CeremonialTrident.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/CobbleCrusher.png b/legacy/public/assets/img/Weapon/CobbleCrusher.png deleted file mode 100644 index 96d503f..0000000 Binary files a/legacy/public/assets/img/Weapon/CobbleCrusher.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DemonCarver.png b/legacy/public/assets/img/Weapon/DemonCarver.png deleted file mode 100644 index a2bbf5d..0000000 Binary files a/legacy/public/assets/img/Weapon/DemonCarver.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DoubleAxe.png b/legacy/public/assets/img/Weapon/DoubleAxe.png deleted file mode 100644 index adcff56..0000000 Binary files a/legacy/public/assets/img/Weapon/DoubleAxe.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DragonboneBokoBat.png b/legacy/public/assets/img/Weapon/DragonboneBokoBat.png deleted file mode 100644 index 6194572..0000000 Binary files a/legacy/public/assets/img/Weapon/DragonboneBokoBat.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DragonboneBokoClub.png b/legacy/public/assets/img/Weapon/DragonboneBokoClub.png deleted file mode 100644 index e568ec2..0000000 Binary files a/legacy/public/assets/img/Weapon/DragonboneBokoClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DragonboneBokoSpear.png b/legacy/public/assets/img/Weapon/DragonboneBokoSpear.png deleted file mode 100644 index abcd2c4..0000000 Binary files a/legacy/public/assets/img/Weapon/DragonboneBokoSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DragonboneMoblinClub.png b/legacy/public/assets/img/Weapon/DragonboneMoblinClub.png deleted file mode 100644 index 5f7d41c..0000000 Binary files a/legacy/public/assets/img/Weapon/DragonboneMoblinClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/DragonboneMoblinSpear.png b/legacy/public/assets/img/Weapon/DragonboneMoblinSpear.png deleted file mode 100644 index 9be608f..0000000 Binary files a/legacy/public/assets/img/Weapon/DragonboneMoblinSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Drillshaft.png b/legacy/public/assets/img/Weapon/Drillshaft.png deleted file mode 100644 index 453ce59..0000000 Binary files a/legacy/public/assets/img/Weapon/Drillshaft.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/EdgeOfDuality.png b/legacy/public/assets/img/Weapon/EdgeOfDuality.png deleted file mode 100644 index fadf85f..0000000 Binary files a/legacy/public/assets/img/Weapon/EdgeOfDuality.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/EightfoldBlade.png b/legacy/public/assets/img/Weapon/EightfoldBlade.png deleted file mode 100644 index 9a26531..0000000 Binary files a/legacy/public/assets/img/Weapon/EightfoldBlade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/EightfoldLongblade.png b/legacy/public/assets/img/Weapon/EightfoldLongblade.png deleted file mode 100644 index 1477db3..0000000 Binary files a/legacy/public/assets/img/Weapon/EightfoldLongblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/EnhancedLizalSpear.png b/legacy/public/assets/img/Weapon/EnhancedLizalSpear.png deleted file mode 100644 index ff0cad8..0000000 Binary files a/legacy/public/assets/img/Weapon/EnhancedLizalSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FarmersPitchfork.png b/legacy/public/assets/img/Weapon/FarmersPitchfork.png deleted file mode 100644 index 796fe11..0000000 Binary files a/legacy/public/assets/img/Weapon/FarmersPitchfork.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FarmingHoe.png b/legacy/public/assets/img/Weapon/FarmingHoe.png deleted file mode 100644 index a61eb10..0000000 Binary files a/legacy/public/assets/img/Weapon/FarmingHoe.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FeatheredEdge.png b/legacy/public/assets/img/Weapon/FeatheredEdge.png deleted file mode 100644 index 03c05c4..0000000 Binary files a/legacy/public/assets/img/Weapon/FeatheredEdge.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FeatheredSpear.png b/legacy/public/assets/img/Weapon/FeatheredSpear.png deleted file mode 100644 index 9674d04..0000000 Binary files a/legacy/public/assets/img/Weapon/FeatheredSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FierceDeitySword.png b/legacy/public/assets/img/Weapon/FierceDeitySword.png deleted file mode 100644 index b7af721..0000000 Binary files a/legacy/public/assets/img/Weapon/FierceDeitySword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FireRod.png b/legacy/public/assets/img/Weapon/FireRod.png deleted file mode 100644 index 603fe21..0000000 Binary files a/legacy/public/assets/img/Weapon/FireRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/FishingHarpoon.png b/legacy/public/assets/img/Weapon/FishingHarpoon.png deleted file mode 100644 index 318a80e..0000000 Binary files a/legacy/public/assets/img/Weapon/FishingHarpoon.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Flameblade.png b/legacy/public/assets/img/Weapon/Flameblade.png deleted file mode 100644 index 00f2d8a..0000000 Binary files a/legacy/public/assets/img/Weapon/Flameblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Flamespear.png b/legacy/public/assets/img/Weapon/Flamespear.png deleted file mode 100644 index 494cd70..0000000 Binary files a/legacy/public/assets/img/Weapon/Flamespear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ForestDwellersSpear.png b/legacy/public/assets/img/Weapon/ForestDwellersSpear.png deleted file mode 100644 index e4d465f..0000000 Binary files a/legacy/public/assets/img/Weapon/ForestDwellersSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ForestDwellersSword.png b/legacy/public/assets/img/Weapon/ForestDwellersSword.png deleted file mode 100644 index 1eea0a0..0000000 Binary files a/legacy/public/assets/img/Weapon/ForestDwellersSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ForkedLizalSpear.png b/legacy/public/assets/img/Weapon/ForkedLizalSpear.png deleted file mode 100644 index ba529e5..0000000 Binary files a/legacy/public/assets/img/Weapon/ForkedLizalSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Frostblade.png b/legacy/public/assets/img/Weapon/Frostblade.png deleted file mode 100644 index 2732bc2..0000000 Binary files a/legacy/public/assets/img/Weapon/Frostblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Frostspear.png b/legacy/public/assets/img/Weapon/Frostspear.png deleted file mode 100644 index ad06c40..0000000 Binary files a/legacy/public/assets/img/Weapon/Frostspear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GerudoScimitar.png b/legacy/public/assets/img/Weapon/GerudoScimitar.png deleted file mode 100644 index 1ef706b..0000000 Binary files a/legacy/public/assets/img/Weapon/GerudoScimitar.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GerudoSpear.png b/legacy/public/assets/img/Weapon/GerudoSpear.png deleted file mode 100644 index e51eefb..0000000 Binary files a/legacy/public/assets/img/Weapon/GerudoSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GiantBoomerang.png b/legacy/public/assets/img/Weapon/GiantBoomerang.png deleted file mode 100644 index f71258e..0000000 Binary files a/legacy/public/assets/img/Weapon/GiantBoomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GoddessSword.png b/legacy/public/assets/img/Weapon/GoddessSword.png deleted file mode 100644 index a25590c..0000000 Binary files a/legacy/public/assets/img/Weapon/GoddessSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GoldenClaymore.png b/legacy/public/assets/img/Weapon/GoldenClaymore.png deleted file mode 100644 index 37caf0f..0000000 Binary files a/legacy/public/assets/img/Weapon/GoldenClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GreatFlameblade.png b/legacy/public/assets/img/Weapon/GreatFlameblade.png deleted file mode 100644 index 5546780..0000000 Binary files a/legacy/public/assets/img/Weapon/GreatFlameblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GreatFrostblade.png b/legacy/public/assets/img/Weapon/GreatFrostblade.png deleted file mode 100644 index d4c4f7a..0000000 Binary files a/legacy/public/assets/img/Weapon/GreatFrostblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GreatThunderblade.png b/legacy/public/assets/img/Weapon/GreatThunderblade.png deleted file mode 100644 index 31015c0..0000000 Binary files a/legacy/public/assets/img/Weapon/GreatThunderblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSpear.png b/legacy/public/assets/img/Weapon/GuardianSpear.png deleted file mode 100644 index 333ef82..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSpearPlus.png b/legacy/public/assets/img/Weapon/GuardianSpearPlus.png deleted file mode 100644 index 710729d..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSpearPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSpearPlusPlus.png b/legacy/public/assets/img/Weapon/GuardianSpearPlusPlus.png deleted file mode 100644 index a06f028..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSpearPlusPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSword.png b/legacy/public/assets/img/Weapon/GuardianSword.png deleted file mode 100644 index 43b2943..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSwordPlus.png b/legacy/public/assets/img/Weapon/GuardianSwordPlus.png deleted file mode 100644 index 5983f47..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSwordPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/GuardianSwordPlusPlus.png b/legacy/public/assets/img/Weapon/GuardianSwordPlusPlus.png deleted file mode 100644 index 2d389e7..0000000 Binary files a/legacy/public/assets/img/Weapon/GuardianSwordPlusPlus.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/IceRod.png b/legacy/public/assets/img/Weapon/IceRod.png deleted file mode 100644 index 7cb5ac5..0000000 Binary files a/legacy/public/assets/img/Weapon/IceRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/IronSledgehammer.png b/legacy/public/assets/img/Weapon/IronSledgehammer.png deleted file mode 100644 index 8d82a5d..0000000 Binary files a/legacy/public/assets/img/Weapon/IronSledgehammer.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/KnightsBroadsword.png b/legacy/public/assets/img/Weapon/KnightsBroadsword.png deleted file mode 100644 index 2ad9021..0000000 Binary files a/legacy/public/assets/img/Weapon/KnightsBroadsword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/KnightsClaymore.png b/legacy/public/assets/img/Weapon/KnightsClaymore.png deleted file mode 100644 index ab3f6eb..0000000 Binary files a/legacy/public/assets/img/Weapon/KnightsClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/KnightsHalberd.png b/legacy/public/assets/img/Weapon/KnightsHalberd.png deleted file mode 100644 index 36aae0d..0000000 Binary files a/legacy/public/assets/img/Weapon/KnightsHalberd.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/KorokLeaf.png b/legacy/public/assets/img/Weapon/KorokLeaf.png deleted file mode 100644 index 78d5ac2..0000000 Binary files a/legacy/public/assets/img/Weapon/KorokLeaf.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LightningRod.png b/legacy/public/assets/img/Weapon/LightningRod.png deleted file mode 100644 index 25807fb..0000000 Binary files a/legacy/public/assets/img/Weapon/LightningRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LightscaleTrident.png b/legacy/public/assets/img/Weapon/LightscaleTrident.png deleted file mode 100644 index c45f117..0000000 Binary files a/legacy/public/assets/img/Weapon/LightscaleTrident.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LizalBoomerang.png b/legacy/public/assets/img/Weapon/LizalBoomerang.png deleted file mode 100644 index 6d43b4b..0000000 Binary files a/legacy/public/assets/img/Weapon/LizalBoomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LizalForkedBoomerang.png b/legacy/public/assets/img/Weapon/LizalForkedBoomerang.png deleted file mode 100644 index 4c493a0..0000000 Binary files a/legacy/public/assets/img/Weapon/LizalForkedBoomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LizalSpear.png b/legacy/public/assets/img/Weapon/LizalSpear.png deleted file mode 100644 index c23bc69..0000000 Binary files a/legacy/public/assets/img/Weapon/LizalSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LizalTriBoomerang.png b/legacy/public/assets/img/Weapon/LizalTriBoomerang.png deleted file mode 100644 index 7a40880..0000000 Binary files a/legacy/public/assets/img/Weapon/LizalTriBoomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LizalfosArm.png b/legacy/public/assets/img/Weapon/LizalfosArm.png deleted file mode 100644 index 00e4a53..0000000 Binary files a/legacy/public/assets/img/Weapon/LizalfosArm.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LynelCrusher.png b/legacy/public/assets/img/Weapon/LynelCrusher.png deleted file mode 100644 index 8db1b3d..0000000 Binary files a/legacy/public/assets/img/Weapon/LynelCrusher.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LynelSpear.png b/legacy/public/assets/img/Weapon/LynelSpear.png deleted file mode 100644 index 13b4e35..0000000 Binary files a/legacy/public/assets/img/Weapon/LynelSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/LynelSword.png b/legacy/public/assets/img/Weapon/LynelSword.png deleted file mode 100644 index 8d8c98e..0000000 Binary files a/legacy/public/assets/img/Weapon/LynelSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MasterSword.png b/legacy/public/assets/img/Weapon/MasterSword.png deleted file mode 100644 index a1eccfb..0000000 Binary files a/legacy/public/assets/img/Weapon/MasterSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MasterSwordAwakened.png b/legacy/public/assets/img/Weapon/MasterSwordAwakened.png deleted file mode 100644 index 058d492..0000000 Binary files a/legacy/public/assets/img/Weapon/MasterSwordAwakened.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MeteorRod.png b/legacy/public/assets/img/Weapon/MeteorRod.png deleted file mode 100644 index 15aa939..0000000 Binary files a/legacy/public/assets/img/Weapon/MeteorRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MightyLynelCrusher.png b/legacy/public/assets/img/Weapon/MightyLynelCrusher.png deleted file mode 100644 index 16116dd..0000000 Binary files a/legacy/public/assets/img/Weapon/MightyLynelCrusher.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MightyLynelSpear.png b/legacy/public/assets/img/Weapon/MightyLynelSpear.png deleted file mode 100644 index 80aeb99..0000000 Binary files a/legacy/public/assets/img/Weapon/MightyLynelSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MightyLynelSword.png b/legacy/public/assets/img/Weapon/MightyLynelSword.png deleted file mode 100644 index 1ec726f..0000000 Binary files a/legacy/public/assets/img/Weapon/MightyLynelSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MoblinArm.png b/legacy/public/assets/img/Weapon/MoblinArm.png deleted file mode 100644 index bd383e2..0000000 Binary files a/legacy/public/assets/img/Weapon/MoblinArm.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MoblinClub.png b/legacy/public/assets/img/Weapon/MoblinClub.png deleted file mode 100644 index 67b054f..0000000 Binary files a/legacy/public/assets/img/Weapon/MoblinClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MoblinSpear.png b/legacy/public/assets/img/Weapon/MoblinSpear.png deleted file mode 100644 index 11f398d..0000000 Binary files a/legacy/public/assets/img/Weapon/MoblinSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/MoonlightScimitar.png b/legacy/public/assets/img/Weapon/MoonlightScimitar.png deleted file mode 100644 index b24cc0b..0000000 Binary files a/legacy/public/assets/img/Weapon/MoonlightScimitar.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/OneHitObliterator.png b/legacy/public/assets/img/Weapon/OneHitObliterator.png deleted file mode 100644 index cd59e38..0000000 Binary files a/legacy/public/assets/img/Weapon/OneHitObliterator.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/OneHitObliteratorCharged.png b/legacy/public/assets/img/Weapon/OneHitObliteratorCharged.png deleted file mode 100644 index 9843e3e..0000000 Binary files a/legacy/public/assets/img/Weapon/OneHitObliteratorCharged.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalBroadsword.png b/legacy/public/assets/img/Weapon/RoyalBroadsword.png deleted file mode 100644 index 5d916fa..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalBroadsword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalClaymore.png b/legacy/public/assets/img/Weapon/RoyalClaymore.png deleted file mode 100644 index ff938be..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalGuardsClaymore.png b/legacy/public/assets/img/Weapon/RoyalGuardsClaymore.png deleted file mode 100644 index f9ddfb1..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalGuardsClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalGuardsSpear.png b/legacy/public/assets/img/Weapon/RoyalGuardsSpear.png deleted file mode 100644 index 05d7c7d..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalGuardsSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalGuardsSword.png b/legacy/public/assets/img/Weapon/RoyalGuardsSword.png deleted file mode 100644 index f217714..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalGuardsSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RoyalHalberd.png b/legacy/public/assets/img/Weapon/RoyalHalberd.png deleted file mode 100644 index 3dedca5..0000000 Binary files a/legacy/public/assets/img/Weapon/RoyalHalberd.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RustyBroadsword.png b/legacy/public/assets/img/Weapon/RustyBroadsword.png deleted file mode 100644 index f1442e3..0000000 Binary files a/legacy/public/assets/img/Weapon/RustyBroadsword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RustyClaymore.png b/legacy/public/assets/img/Weapon/RustyClaymore.png deleted file mode 100644 index 6ac6305..0000000 Binary files a/legacy/public/assets/img/Weapon/RustyClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/RustyHalberd.png b/legacy/public/assets/img/Weapon/RustyHalberd.png deleted file mode 100644 index 28f2dc4..0000000 Binary files a/legacy/public/assets/img/Weapon/RustyHalberd.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SavageLynelCrusher.png b/legacy/public/assets/img/Weapon/SavageLynelCrusher.png deleted file mode 100644 index 937953f..0000000 Binary files a/legacy/public/assets/img/Weapon/SavageLynelCrusher.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SavageLynelSpear.png b/legacy/public/assets/img/Weapon/SavageLynelSpear.png deleted file mode 100644 index eaeff0f..0000000 Binary files a/legacy/public/assets/img/Weapon/SavageLynelSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SavageLynelSword.png b/legacy/public/assets/img/Weapon/SavageLynelSword.png deleted file mode 100644 index c748a7c..0000000 Binary files a/legacy/public/assets/img/Weapon/SavageLynelSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ScimitarOfTheSeven.png b/legacy/public/assets/img/Weapon/ScimitarOfTheSeven.png deleted file mode 100644 index 60c1145..0000000 Binary files a/legacy/public/assets/img/Weapon/ScimitarOfTheSeven.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SeaBreezeBoomerang.png b/legacy/public/assets/img/Weapon/SeaBreezeBoomerang.png deleted file mode 100644 index 657f4d9..0000000 Binary files a/legacy/public/assets/img/Weapon/SeaBreezeBoomerang.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SerpentineSpear.png b/legacy/public/assets/img/Weapon/SerpentineSpear.png deleted file mode 100644 index 3d38f0c..0000000 Binary files a/legacy/public/assets/img/Weapon/SerpentineSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SilverLongsword.png b/legacy/public/assets/img/Weapon/SilverLongsword.png deleted file mode 100644 index 5ec6f5b..0000000 Binary files a/legacy/public/assets/img/Weapon/SilverLongsword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SilverscaleSpear.png b/legacy/public/assets/img/Weapon/SilverscaleSpear.png deleted file mode 100644 index d6da890..0000000 Binary files a/legacy/public/assets/img/Weapon/SilverscaleSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SoldiersBroadsword.png b/legacy/public/assets/img/Weapon/SoldiersBroadsword.png deleted file mode 100644 index 4352bb1..0000000 Binary files a/legacy/public/assets/img/Weapon/SoldiersBroadsword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SoldiersClaymore.png b/legacy/public/assets/img/Weapon/SoldiersClaymore.png deleted file mode 100644 index 2313e85..0000000 Binary files a/legacy/public/assets/img/Weapon/SoldiersClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SoldiersSpear.png b/legacy/public/assets/img/Weapon/SoldiersSpear.png deleted file mode 100644 index 299e354..0000000 Binary files a/legacy/public/assets/img/Weapon/SoldiersSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SoupLadle.png b/legacy/public/assets/img/Weapon/SoupLadle.png deleted file mode 100644 index 4642dfd..0000000 Binary files a/legacy/public/assets/img/Weapon/SoupLadle.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpikedBokoBat.png b/legacy/public/assets/img/Weapon/SpikedBokoBat.png deleted file mode 100644 index d838826..0000000 Binary files a/legacy/public/assets/img/Weapon/SpikedBokoBat.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpikedBokoClub.png b/legacy/public/assets/img/Weapon/SpikedBokoClub.png deleted file mode 100644 index d503731..0000000 Binary files a/legacy/public/assets/img/Weapon/SpikedBokoClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpikedBokoSpear.png b/legacy/public/assets/img/Weapon/SpikedBokoSpear.png deleted file mode 100644 index 1d33e3b..0000000 Binary files a/legacy/public/assets/img/Weapon/SpikedBokoSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpikedMoblinClub.png b/legacy/public/assets/img/Weapon/SpikedMoblinClub.png deleted file mode 100644 index 7e5a7c7..0000000 Binary files a/legacy/public/assets/img/Weapon/SpikedMoblinClub.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpikedMoblinSpear.png b/legacy/public/assets/img/Weapon/SpikedMoblinSpear.png deleted file mode 100644 index ad14d2c..0000000 Binary files a/legacy/public/assets/img/Weapon/SpikedMoblinSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SpringLoadedHammer.png b/legacy/public/assets/img/Weapon/SpringLoadedHammer.png deleted file mode 100644 index d8bbce8..0000000 Binary files a/legacy/public/assets/img/Weapon/SpringLoadedHammer.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/StoneSmasher.png b/legacy/public/assets/img/Weapon/StoneSmasher.png deleted file mode 100644 index 8366fd4..0000000 Binary files a/legacy/public/assets/img/Weapon/StoneSmasher.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Sword.png b/legacy/public/assets/img/Weapon/Sword.png deleted file mode 100644 index 97e8158..0000000 Binary files a/legacy/public/assets/img/Weapon/Sword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/SwordOfTheSixSages.png b/legacy/public/assets/img/Weapon/SwordOfTheSixSages.png deleted file mode 100644 index 7bc9a33..0000000 Binary files a/legacy/public/assets/img/Weapon/SwordOfTheSixSages.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ThrowingSpear.png b/legacy/public/assets/img/Weapon/ThrowingSpear.png deleted file mode 100644 index eb34cc2..0000000 Binary files a/legacy/public/assets/img/Weapon/ThrowingSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Thunderblade.png b/legacy/public/assets/img/Weapon/Thunderblade.png deleted file mode 100644 index e2eb0ac..0000000 Binary files a/legacy/public/assets/img/Weapon/Thunderblade.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Thunderspear.png b/legacy/public/assets/img/Weapon/Thunderspear.png deleted file mode 100644 index 73dbc9b..0000000 Binary files a/legacy/public/assets/img/Weapon/Thunderspear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ThunderstormRod.png b/legacy/public/assets/img/Weapon/ThunderstormRod.png deleted file mode 100644 index ea51e73..0000000 Binary files a/legacy/public/assets/img/Weapon/ThunderstormRod.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Torch.png b/legacy/public/assets/img/Weapon/Torch.png deleted file mode 100644 index db00bb3..0000000 Binary files a/legacy/public/assets/img/Weapon/Torch.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/TravelersClaymore.png b/legacy/public/assets/img/Weapon/TravelersClaymore.png deleted file mode 100644 index 781445b..0000000 Binary files a/legacy/public/assets/img/Weapon/TravelersClaymore.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/TravelersSpear.png b/legacy/public/assets/img/Weapon/TravelersSpear.png deleted file mode 100644 index c4c55e9..0000000 Binary files a/legacy/public/assets/img/Weapon/TravelersSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/TravelersSword.png b/legacy/public/assets/img/Weapon/TravelersSword.png deleted file mode 100644 index e02635c..0000000 Binary files a/legacy/public/assets/img/Weapon/TravelersSword.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/TreeBranch.png b/legacy/public/assets/img/Weapon/TreeBranch.png deleted file mode 100644 index 05eec11..0000000 Binary files a/legacy/public/assets/img/Weapon/TreeBranch.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ViciousSickle.png b/legacy/public/assets/img/Weapon/ViciousSickle.png deleted file mode 100644 index a685098..0000000 Binary files a/legacy/public/assets/img/Weapon/ViciousSickle.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Weapon.png b/legacy/public/assets/img/Weapon/Weapon.png deleted file mode 100644 index 509467a..0000000 Binary files a/legacy/public/assets/img/Weapon/Weapon.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/Windcleaver.png b/legacy/public/assets/img/Weapon/Windcleaver.png deleted file mode 100644 index 6e64a15..0000000 Binary files a/legacy/public/assets/img/Weapon/Windcleaver.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/WoodcuttersAxe.png b/legacy/public/assets/img/Weapon/WoodcuttersAxe.png deleted file mode 100644 index 31b4359..0000000 Binary files a/legacy/public/assets/img/Weapon/WoodcuttersAxe.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/WoodenMop.png b/legacy/public/assets/img/Weapon/WoodenMop.png deleted file mode 100644 index a3706c1..0000000 Binary files a/legacy/public/assets/img/Weapon/WoodenMop.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ZoraSpear.png b/legacy/public/assets/img/Weapon/ZoraSpear.png deleted file mode 100644 index 7468cd9..0000000 Binary files a/legacy/public/assets/img/Weapon/ZoraSpear.png and /dev/null differ diff --git a/legacy/public/assets/img/Weapon/ZoraSword.png b/legacy/public/assets/img/Weapon/ZoraSword.png deleted file mode 100644 index 4e235f9..0000000 Binary files a/legacy/public/assets/img/Weapon/ZoraSword.png and /dev/null differ diff --git a/manual/COMMANDS.md b/manual/COMMANDS.md index 76d44fa..51fb885 100644 --- a/manual/COMMANDS.md +++ b/manual/COMMANDS.md @@ -8,10 +8,8 @@ core commands: # PMDM # Stage 1 - !core-add ITEM: - Add ITEM to PMDM - !core-add-one ITEM: - Add one ITEM to PMDM + !core-add Item: + Add Item to PMDM !core-remove-held: Remove held items !core-hold SLOT: @@ -54,6 +52,10 @@ core commands: !core-set-gdt FLAG VALUE: Set GDT FLAG to VALUE + !core-aslr NUMBER: + Set the upper 32 bits of address in ASLR region. + This can only be done when the game is closed + extra: @@ -107,9 +109,9 @@ runtime: annotations: global: // I guess these are technically features? - (FEATURE) + :enable FEATURE Enable Feature - (no-FEATURE) + :disable FEATURE Disable Feature (menu-overload) Start menu overload diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..08918ba --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8196 @@ +{ + "name": "botw-ist", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "workspaces": [ + "packages/app", + "packages/extension-api", + "packages/intwc", + "packages/item-assets", + "packages/item-system", + "packages/localization", + "packages/monaco-typescript-contrib", + "packages/monaco-editor-contrib", + "packages/runtime-wasm/pkg", + "packages/workex" + ], + "devDependencies": { + "@eslint/js": "^9.17.0", + "@modyfi/vite-plugin-yaml": "^1.1.0", + "@types/react": "^18.3.16", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.17.0", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.16", + "globals": "^15.13.0", + "prettier": "^3.4.2", + "storybook": "^8.4.7", + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.0", + "vite": "^5.4.11", + "vite-tsconfig-paths": "^5.1.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@catppuccin/palette": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@catppuccin/palette/-/palette-1.7.1.tgz", + "integrity": "sha512-aRc1tbzrevOTV7nFTT9SRdF26w/MIwT4Jwt4fDMc9itRZUDXCuEDBLyz4TQMlqO9ZP8mf5Hu4Jr6D03NLFc6Gw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/catppuccin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/catppuccin" + } + ], + "license": "MIT" + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "peerDependencies": { + "@floating-ui/dom": ">=1.5.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, + "node_modules/@fluentui/keyboard-keys": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.8.tgz", + "integrity": "sha512-iUSJUUHAyTosnXK8O2Ilbfxma+ZyZPMua5vB028Ys96z80v+LFwntoehlFsdH3rMuPsA8GaC1RE7LMezwPBPdw==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.1.14", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.14.tgz", + "integrity": "sha512-tIH8EhvjZF4MhxSjqrWOyodrQQW+RlVZqxuNFQF5OWRdSqcIK8g+Z+UbC5fYHQooCgVsthk2mFurfGMKFtf9ug==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-accordion": { + "version": "9.5.12", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.5.12.tgz", + "integrity": "sha512-xpY78JuTyxZF+id+GUxIMfFQG5mGkW5WvNW/H2t9kPKohYHfzQXTp7XUIkfSaqGMg/XjezqjtkJcCd+z9oKXnw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-motion-components-preview": "^0.4.1", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-accordion/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-accordion/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.124", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.124.tgz", + "integrity": "sha512-yFBo3B5H9hnoaXxlkuz8wRz04DEyQ+ElYA/p5p+Vojf19Zuta8DmFZZ6JtWdtxcdnnQ4LvAfC5OYYlzdReozPA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-avatar": "^9.6.29", + "@fluentui/react-button": "^9.3.83", + "@fluentui/react-icons": "^2.0.239", + "@fluentui/react-jsx-runtime": "^9.0.39", + "@fluentui/react-tabster": "^9.21.5", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.10", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.13.12", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.13.12.tgz", + "integrity": "sha512-1qNa4Yux3X3l9pQMGnANkZcNJA4rtCNnaImW5rHDAXhRzvIkQtypN0bRIsWVZqeQEc5bABh9QJaItdOo+TPelw==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.6.47", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.47.tgz", + "integrity": "sha512-ykEF6XVd+2vB7RghJaqcMZRpqbf6ZM7UgOVKLFIEAy8qiX2Fwa2VzzA3rhTQoBB2QvaXGrFKeDzN+bTkMkXKBg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-badge": "^9.2.48", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-popover": "^9.9.29", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-tooltip": "^9.5.2", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-avatar/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.2.48", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.48.tgz", + "integrity": "sha512-yVP4SaLVjr97IvicxhlfECxB92MbDLIn+nevcGWV28/H7qWypZiCC8DXfJKE/QDVyrClefozqEIeww7lhUjcJg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.0.47", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.47.tgz", + "integrity": "sha512-r+sDXZWWVuwsS4JW+0tpOoC4F3iDCEWMtD0EOtc5wpwF/WASQWIvikzUDOS1N9ACTHVoyq1gPqQmECBHWCloQw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-link": "^9.3.5", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.3.98", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.98.tgz", + "integrity": "sha512-ET548xw82eXBz43tyxoswv51XnusSK2sq/mm9KrlNpSVbzjyOHxfG0ZQ88KZCIcFSqq/8ZpLG23tihlKOl/n+g==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.0.100", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.100.tgz", + "integrity": "sha512-PLSWvFzNR9HvVQcMGbG1OIj2TjSlGVMV/6Nli/YaICRvGjjEX1f37NAu3yotEbxqZavJg7j8ekJ/dQqXPGv5HA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-text": "^9.4.30", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-carousel": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.4.3.tgz", + "integrity": "sha512-wOd+cWV8b+2OOfITVmFY7fjouk28JtPTm5i7b3+1n0O8GMkkoI6dvpMyp+VXj4NnoYD86umrpXFGoSLX2UAqXw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "embla-carousel": "^8.5.1", + "embla-carousel-autoplay": "^8.5.1", + "embla-carousel-fade": "^8.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-carousel/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-carousel/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.2.44", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.44.tgz", + "integrity": "sha512-sVY0kKg3FMgzMMfGPbcM71dVqWYbOrkF7qtDDwwFeSCnk3km1SHxeNCR4KRIvtTriosvjkoo3u981ldLsufSWw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.13.15", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.13.15.tgz", + "integrity": "sha512-v03PcpOfeylfmF48SQ+FMEctafysMcScbVXej63fTiCXBZMxrdv3sJUG2Lf8ZbvQGVdEYad6l9J+Xsk1mhjr9Q==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-combobox/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.56.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.56.8.tgz", + "integrity": "sha512-7Japh4zntMzCha2iuDYPPPCabvETpmJpxiLJptVR/iq7NdjYgpSX7RUkuIjjJOyYyvk6e1bQW9KXO6Eg3HyMPA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-accordion": "^9.5.12", + "@fluentui/react-alert": "9.0.0-beta.124", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-avatar": "^9.6.47", + "@fluentui/react-badge": "^9.2.48", + "@fluentui/react-breadcrumb": "^9.0.47", + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-card": "^9.0.100", + "@fluentui/react-carousel": "^9.4.3", + "@fluentui/react-checkbox": "^9.2.44", + "@fluentui/react-combobox": "^9.13.15", + "@fluentui/react-dialog": "^9.11.26", + "@fluentui/react-divider": "^9.2.80", + "@fluentui/react-drawer": "^9.6.6", + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-image": "^9.1.78", + "@fluentui/react-infobutton": "9.0.0-beta.102", + "@fluentui/react-infolabel": "^9.0.54", + "@fluentui/react-input": "^9.4.96", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-link": "^9.3.5", + "@fluentui/react-menu": "^9.14.24", + "@fluentui/react-message-bar": "^9.2.19", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-overflow": "^9.2.5", + "@fluentui/react-persona": "^9.2.106", + "@fluentui/react-popover": "^9.9.29", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-progress": "^9.1.94", + "@fluentui/react-provider": "^9.18.2", + "@fluentui/react-radio": "^9.2.39", + "@fluentui/react-rating": "^9.0.26", + "@fluentui/react-search": "^9.0.26", + "@fluentui/react-select": "^9.1.94", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-skeleton": "^9.1.23", + "@fluentui/react-slider": "^9.2.3", + "@fluentui/react-spinbutton": "^9.2.95", + "@fluentui/react-spinner": "^9.5.5", + "@fluentui/react-swatch-picker": "^9.1.17", + "@fluentui/react-switch": "^9.1.101", + "@fluentui/react-table": "^9.15.26", + "@fluentui/react-tabs": "^9.6.5", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-tag-picker": "^9.3.13", + "@fluentui/react-tags": "^9.3.27", + "@fluentui/react-teaching-popover": "^9.1.26", + "@fluentui/react-text": "^9.4.30", + "@fluentui/react-textarea": "^9.3.95", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-toast": "^9.3.63", + "@fluentui/react-toolbar": "^9.2.13", + "@fluentui/react-tooltip": "^9.5.2", + "@fluentui/react-tree": "^9.8.11", + "@fluentui/react-utilities": "^9.18.19", + "@fluentui/react-virtualizer": "9.0.0-alpha.89", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.11.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.11.26.tgz", + "integrity": "sha512-I5/5zn843DQyOQ4mYuLqvgiA1UHS7wMYdwLFt5wGIQdk8oXgoCMwCJakFGU3/6JLWBl+YRxCd0RYMkCPuYdk1g==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-motion-components-preview": "^0.4.1", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-dialog/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-dialog/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.2.80", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.80.tgz", + "integrity": "sha512-8SahbCicYzoi75etgJwOI+YDh09/eGA9Pf0PUbpymY8c8+voH/o7OOxwiV45A8VlxZFd5K9TwA0MVtmxsiClDQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.6.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.6.6.tgz", + "integrity": "sha512-Ky9Si3u5domFfkVMa/CclebHkj4OG+NQ4ut2yY0GYGAVnON0F1B3HWlqtmBId63gQNzdarosKM5WMjsSaDRMFA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-dialog": "^9.11.26", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.1.83", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.83.tgz", + "integrity": "sha512-+Gm6RWcr32C+t+PVpqPRTzDNDDG01IUnevPJR2t2ROcr+rDmqGA8tQ0eT7Nl6ZpWDZeOHOHXR13YtMPEjq6VPw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-field/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.270", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.270.tgz", + "integrity": "sha512-XFAUxbOTH5gb/eTZ5UDR/841tbNskr2SNa/hshsQdojyEKMjBxNNcXo2ruesdfCGKsz/KOlmSh2sZu7NmN2N7Q==", + "license": "MIT", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-image": { + "version": "9.1.78", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.78.tgz", + "integrity": "sha512-/5bfyURPVgW2yJyFwsW5x+rCcS3yxZk+7vhrDPIQn/WzZ4cpO7XNQQvoeqZlpC/DbmPHJWjPzRi2kDwikuZgNg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.102", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.102.tgz", + "integrity": "sha512-3kA4F0Vga8Ds6JGlBajLCCDOo/LmPuS786Wg7ui4ZTDYVIMzy1yp2XuVcZniifBFvEp0HQCUoDPWUV0VI3FfzQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.237", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-popover": "^9.9.6", + "@fluentui/react-tabster": "^9.21.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.0.54", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.54.tgz", + "integrity": "sha512-DiU/mnt4TYAyrAYgfv8yFkYyrsKGsrkw09zUBl4yPXxz6fjtULQaAc1ahty8bndjuCrz3edDr8jbrHLVDB18Lg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-popover": "^9.9.29", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.4.96", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.96.tgz", + "integrity": "sha512-Fry5AwRwGotZmuSEYj7WNyGI2yYR+7kSO+2tqPy1HtajUVz+JfHbn95wem1ZoSkOUnuj15fmSuXJAAN5q967ug==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.0.48", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.48.tgz", + "integrity": "sha512-Awk9rsbXsANqR+yCRSHlbVySn2jjP9FU94Jn+phe+USV93Pi32qJCwjL0zymIOIEYIeqdwngGHvSa+nrAx+jRQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/@fluentui/react-label": { + "version": "9.1.81", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.81.tgz", + "integrity": "sha512-Hv+rEbZDdLDTwrNqiDG66Yy21Qh2kpXg+etCfbqjF5ENua5J+I2iAdxDYwUUip7Hq12VckKnsqjytgdIhwyO/A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.3.5.tgz", + "integrity": "sha512-YAsnt0WOQvPA2esHjK9uuoxVuQVAN12nBO/DuNlqW9sv7Rpc2jHU/4de3gR608uGEWtp/K0bwyafo+oTtMzJKQ==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.14.24", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.14.24.tgz", + "integrity": "sha512-IJxvGQdJ2bMIYmpIpJixpJ55OqMLJUF6eAmLGZOMlk9TJiQxFKO04v6LYIffMFAuMknhwNfW3hbt6uU+hHcItA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-menu/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.2.19", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.2.19.tgz", + "integrity": "sha512-wiO3kW8rCuCTscBZMUS9Lmt8e6DZiziwspjM/5ELu7DF6TQtIgPRe0CStL2UZEXvyLcGTpCCCj64LiTQ7UQhtA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-link": "^9.3.5", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion": { + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.6.5.tgz", + "integrity": "sha512-EDgB/BqqIQuFiQk5dei92RR+/W9zZ15DaeDzDMqCMYgkipnYuJ2xE18cEHyuDpUVCQL4Uw25y3oLqLxb4fI6iA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion-components-preview": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.4.1.tgz", + "integrity": "sha512-wHiwrhKpOACGHW4ozJjq8L598OKPk2IiSOT14IXOQ8XMOpKtusYO6CJ1nHukzFl3sQ/cx2ADIFoqaFJ1/1zYXg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-motion": "*", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.2.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.2.5.tgz", + "integrity": "sha512-eH4QseZFy3S9qhOEG+0t8d2o5vY/0jqeJqcjsoXyh6WZskxhCpCxEWcvufPxTe0Y3YolMzYvIzTBmSgpRNljzg==", + "license": "MIT", + "dependencies": { + "@fluentui/priority-overflow": "^9.1.14", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-overflow/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-overflow/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.2.106", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.106.tgz", + "integrity": "sha512-QMU4RhGG4tVF09zniSlWtsg9p9RQ0MT8XOSIOSsaypATml8I8L3bVrIluKbJjLqR5BrxVpt/TAzrB0H0qUcD1g==", + "license": "MIT", + "dependencies": { + "@fluentui/react-avatar": "^9.6.47", + "@fluentui/react-badge": "^9.2.48", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.9.29", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.9.29.tgz", + "integrity": "sha512-RAkL9rqUetCL+ie6AoChNwjKEVZweEyOGwExOIZW0U3kZ9dv87RHWFZrzl3EtiXaJ0c3BpvuMgZWpCVc+XKw2g==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-popover/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.4.40", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.40.tgz", + "integrity": "sha512-YLpazsKAsc9u6x7z9E7vAIUcn8829PTECOtWNwDXLc9iSFKtTIO1HntybGkEtptb+2TYiquJgG+Lpg9YKFkaYQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-positioning": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.16.0.tgz", + "integrity": "sha512-tVmsiH8bv654+dJYm6bmDA5E+Oo7j9J15tzlWvl7EowE9EBPNqZah5rTAyCoODkdU23pJcq43o2QpLGjPc36XQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.2.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.1.94", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.94.tgz", + "integrity": "sha512-Tfff8O5xMpji2oBeOuhp/yQolUqkpTQ1Ml8kIS/QS+nQ36XRAd/CSnI/OGyd/2Qsa9g93+XgXyopUemz1bUPAA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.18.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.18.2.tgz", + "integrity": "sha512-OVOGSYtcgl13nsQEIDEvhdL/d9LbA0gS87r4Kb2lWIn3iK3bLSjeYbNi++WLMQspaAI38jLSLrXyEoInN1WOdg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/core": "^1.16.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.2.39", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.39.tgz", + "integrity": "sha512-avEG2oM31ty69D4+OrZCakClleGgkJiqPyx6aVqyskH7Hy0/iC3TDMDpwkSY5QeLOvy+dNyhCNxY+rMuuVHAgA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-rating": { + "version": "9.0.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.0.26.tgz", + "integrity": "sha512-SEL1uiiij+DMUTtvrJnawnni7xzbl1JQ3IvMN1I5PYw8uJNTL+JylF1P8/rltOd9xOCat1wsu7WsmzsahKnIUA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-search": { + "version": "9.0.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.0.26.tgz", + "integrity": "sha512-pXmIG6L1bQk2eWPnnvFDczn67PcXjAuI/tT1N9tD+/iAc0SCz0sWN9S2rKTaYrrSVhDbUbM1EKyGci+MVlsW/A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-input": "^9.4.96", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.1.94", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.94.tgz", + "integrity": "sha512-kb0yeBQ41BlWNQZ/pjbgl21VFwlZc9hmm8YYriR+bc6cvRSj/oLAFj5/3XtB0DhjYO/IorvxCVI5vkSZnGgrnQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.21.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.21.2.tgz", + "integrity": "sha512-5hw9CfCmKaEbxmFi+ZF4EZzYWFKrfRLq9pXFIoJWprP1D3ZAds/ymtIOG/CsJzig8zQ1LQ3cNSUzNB75XWg6IQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-theme": "^9.1.24", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.1.23", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.1.23.tgz", + "integrity": "sha512-lDNP5xYnWJj6IHNd7FHVCi+p2XV7d2cIkwMJ5usKeoTTnWr/1E2T8P+pNsOyku68/r6zuozqtCOmCI2u/OLo4g==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.2.3.tgz", + "integrity": "sha512-2vaAR6eTDwhQf5t5d7nb+oHEbzD3nKbBnkdOVAieknmQV/Xxum8P6v1KY8FmYmwFhjxKaUYIZ9j9/mT95DEo+A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.2.95", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.95.tgz", + "integrity": "sha512-hJMXr+7X0wJhLQq0XmfQ2FLxvUxDTeUkHlEowtYjJJJDoepzuTm4chdyLz+Q4MSEV+NiKioLVMfNs750S7Z0Lw==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.5.5.tgz", + "integrity": "sha512-PQSU0kJxOXBLwR/bNO996HkSqZ6mVWhDeT6Bt0gP+D+USl3Akj9cUnNtlzw5781tcdks/7U7SovqqKym3HTKoA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-swatch-picker": { + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.1.17.tgz", + "integrity": "sha512-VG44DspajQFOvFpe71NyB7q1fBovtB41udvJCiaD5NVsUFo7THgtjJrgGjd4EUeruuoQ4SxJEv3T7HymFL64BA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-swatch-picker/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-swatch-picker/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.1.101", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.101.tgz", + "integrity": "sha512-7m7FiKVAyVOQbdeoiHWMbtnGxlcnSm7quhs9OySuP4fGRd0nR1DalmjOE4h/tbysyF/n0FcgGu3bD0dh5VgD7g==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-label": "^9.1.81", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.15.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.15.26.tgz", + "integrity": "sha512-EMYQXxjtVYj6moL5lVQiA5hVEqm2raDv1nphX2wUGRb6Yy8YS5gS42B5DtNMPPnc6sDPwxhrqJL7BIeIHy5ILA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-avatar": "^9.6.47", + "@fluentui/react-checkbox": "^9.2.44", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-radio": "^9.2.39", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-table/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.6.5.tgz", + "integrity": "sha512-IulnVxI6gQEfmsdlVjmP33qtyzzAw2J/oBlXfSPz2JbARx6KEUMak7YNnIWm1Jv35lphQBuL6WVItDWY+9+xFg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabs/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-tabs/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.23.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.23.2.tgz", + "integrity": "sha512-DG1rZy8dkD24urQQywhRPfo13qEALCHUWSBmuAYnZ9wAHkGRbDVgdGZLEEUkvP5a6PxdDsFD5AGnC4C+56gKOg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.6.0", + "tabster": "^8.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tag-picker": { + "version": "9.3.13", + "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.3.13.tgz", + "integrity": "sha512-F4TLdVR+ikGqFZVuM6CqVdCTqNYzJm5YY6cvMXlbN/nOFM6/sW/cxrdtNQ2tfgp+k4HXIzqOvd2ohtCca9DOBQ==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-combobox": "^9.13.15", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-tags": "^9.3.27", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tag-picker/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-tag-picker/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.3.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.3.27.tgz", + "integrity": "sha512-lJDXEI8KClPMZTnnviVegcvGIvWQXXT/fAq6cZm30EnzmM3hRLJFMDFpCLoCAWoYsK2Nyh2xyTny4Vr+/dE4Vg==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-avatar": "^9.6.47", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.1.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.1.26.tgz", + "integrity": "sha512-AtMHNS8cQDVJoWpJsSInvNFcwUA+4bC+qXSAjxXK9CYAxztkqGmFoADqlvxSU7QufNwI/9aBR0AcmkefyM4/Ew==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-popover": "^9.9.29", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-teaching-popover/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.4.30", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.30.tgz", + "integrity": "sha512-LwJL+daufTuTmelIKIYfzKjb6WdHzq4GiOD1COjElyAd8K5/hrsUB+oqKs6UxCRRDzHmuChLvInGiVIyAVunPw==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.3.95", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.95.tgz", + "integrity": "sha512-f9MUl9nPDnVMINmK+rnJbxP6RjSadg2DxM2YubxivCMGEapnfeOLuWnBO82RXSMs60o66Zt3FUVmsGjCZ/HJ1A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.1.83", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.1.24", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.24.tgz", + "integrity": "sha512-OhVKYD7CMYHxzJEn4PtIszledj8hbQJNWBMfIZsp4Sytdp9vCi0txIQUx4BhS1WqtQPhNGCF16eW9Q3NRrnIrQ==", + "license": "MIT", + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.21", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.3.63", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.63.tgz", + "integrity": "sha512-jNl7pcPpkUL31C9bc/Njikojd6ozfOUqa2l9PaKdfXg4FUDC/3lMELhFyjUfyWZD8cGsRaqRTp45DgCajd7ahg==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-motion-components-preview": "^0.4.1", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.2.13", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.2.13.tgz", + "integrity": "sha512-6lY8YgxxstywsMh+6c66JNr1PtGE2FmPHRU5yNt0qYaZftXpOFg9UZrDcK00Um2sHTGXDZe+XlsWe4rsI1UdYQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-divider": "^9.2.80", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-radio": "^9.2.39", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-toolbar/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.5.2.tgz", + "integrity": "sha512-hFx63frEUB0irYg7nBbTZh/1u4Ho57BBcpmrTTV/rq5NFlVAJJGWI9jj84utk7T+nFnnA9NUfvdy8KorCoxtkQ==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-portal": "^9.4.40", + "@fluentui/react-positioning": "^9.16.0", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.8.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.8.11.tgz", + "integrity": "sha512-gKWzjgfjl4uVzX6fh9TAgVmil4ihBW1q84y1TIRdfB+nkLfE91KUqJRVgKqfKj3tL6mjkcvicJOZz0EKvt6iOg==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.13.12", + "@fluentui/react-avatar": "^9.6.47", + "@fluentui/react-button": "^9.3.98", + "@fluentui/react-checkbox": "^9.2.44", + "@fluentui/react-context-selector": "^9.1.71", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-motion": "^9.6.5", + "@fluentui/react-motion-components-preview": "^0.4.1", + "@fluentui/react-radio": "^9.2.39", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-tabster": "^9.23.2", + "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree/node_modules/@fluentui/react-context-selector": { + "version": "9.1.71", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.71.tgz", + "integrity": "sha512-rBm3+e/RPERRdW8xbL7+JgUHApNkoVOXoRfzva4qWF4dOudmDytPobzNNAyNXQXSbFZoeBYiCQ62OZf7wVpE5A==", + "license": "MIT", + "dependencies": { + "@fluentui/react-utilities": "^9.18.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-tree/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.18.19", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.18.19.tgz", + "integrity": "sha512-cBYq2cRc+ofVv4DTgULX5ez6IN/DiZw8IC17giA7NyxGw9ed0Y2p7nqnz/tIa655tY/ZIw5oz+bRJrEPkpzA2g==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-shared-contexts": "^9.21.2", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.89", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.89.tgz", + "integrity": "sha512-O4nw6FxlVZHQ6B8jCqpsDo308CEyyNNCFOqqC83c7KhA43QczwX0wif8UVlkGKPjY4iwBfEB4fGRO68khN/KRQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.48", + "@fluentui/react-shared-contexts": "^9.21.2", + "@fluentui/react-utilities": "^9.18.19", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.21", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.21.tgz", + "integrity": "sha512-xQ1T56sNgDFGl+kJdIwhz67mHng8vcwO7Dvx5Uja4t+NRULQBgMcJ4reUo4FGF3TjufHj08pP0/OnKQgnOaSVg==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@griffel/core": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.18.2.tgz", + "integrity": "sha512-odJspTMohsYZLSlO/oKsf6El6px1vg1461CpPverOzS9f0xaUKh/ZGenW+MjyyZ3aQ6adkPzcr/my6JFH/zdXQ==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.3.0", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.27", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.27.tgz", + "integrity": "sha512-985A8iEBo++h9u96dbj3Kj5hdsBWbpkkwFpy0W8EGL0VRCzZmpb0AlWuq9pDJZACS6eZ2GAb/f9CqgVAgnTnOg==", + "license": "MIT", + "dependencies": { + "@griffel/core": "^1.18.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.3.0.tgz", + "integrity": "sha512-bHwD3sUE84Xwv4dH011gOKe1jul77M1S6ZFN9Tnq8pvZ48UMdY//vtES6fv7GRS5wXYT4iqxQPBluAiYAfkpmw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modyfi/vite-plugin-yaml": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@modyfi/vite-plugin-yaml/-/vite-plugin-yaml-1.1.0.tgz", + "integrity": "sha512-L26xfzkSo1yamODCAtk/ipVlL6OEw2bcJ92zunyHu8zxi7+meV0zefA9xscRMDCsMY8xL3C3wi3DhMiPxcbxbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "5.1.0", + "js-yaml": "4.1.0", + "tosource": "2.0.0-alpha.3" + }, + "peerDependencies": { + "vite": "^3.2.7 || ^4.0.5 || ^5.0.5" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pistonite/intwc": { + "resolved": "packages/intwc", + "link": true + }, + "node_modules/@pistonite/monaco-typescript-contrib": { + "resolved": "packages/monaco-typescript-contrib", + "link": true + }, + "node_modules/@pistonite/pure": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@pistonite/pure/-/pure-0.0.17.tgz", + "integrity": "sha512-5f31NlEEkuWu8I33tf9NG+YmrKf6SbKt/hPNVIakcrBs40F9tMN2GYijFdtr0S5/dnzp6btGrbOXhmhqlSsY7A==", + "license": "MIT", + "dependencies": { + "@types/file-saver": "^2.0.7", + "denque": "2.1.0", + "file-saver": "2.0.5" + } + }, + "node_modules/@pistonite/pure-react": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@pistonite/pure-react/-/pure-react-0.0.5.tgz", + "integrity": "sha512-MzWsQzTczPY2BkOWFdCz49LSvljfwyCFbenQzOVHzvlCbmeTuwY2nzUMxMSJh1cvBv5aVQM9ih1erio//HM3Kg==", + "license": "MIT", + "dependencies": { + "@pistonite/pure": "^0.0.14" + }, + "peerDependencies": { + "react": "^18" + } + }, + "node_modules/@pistonite/pure-react/node_modules/@pistonite/pure": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@pistonite/pure/-/pure-0.0.14.tgz", + "integrity": "sha512-p0GOg8wQ1ZUwsQGwNoS/rL1/nlzVsorBgPP4p+GFhMUHzC+wJbnzR76c+ucyATjTLBTsvBZCBdkXrdRqrdT3Ig==", + "license": "MIT", + "dependencies": { + "@types/file-saver": "^2.0.7", + "denque": "2.1.0", + "file-saver": "2.0.5" + } + }, + "node_modules/@pistonite/skybook-extension-api": { + "resolved": "packages/extension-api", + "link": true + }, + "node_modules/@rollup/plugin-virtual": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", + "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", + "integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz", + "integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz", + "integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz", + "integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz", + "integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz", + "integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz", + "integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz", + "integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz", + "integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz", + "integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz", + "integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz", + "integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz", + "integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz", + "integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz", + "integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz", + "integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz", + "integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz", + "integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz", + "integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@storybook/core": { + "version": "8.4.7", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.4.7.tgz", + "integrity": "sha512-7Z8Z0A+1YnhrrSXoKKwFFI4gnsLbWzr8fnDCU6+6HlDukFYh8GHRcZ9zKfqmy6U3hw2h8H5DrHsxWfyaYUUOoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf": "^0.1.11", + "better-opn": "^3.0.2", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0", + "esbuild-register": "^3.5.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "process": "^0.11.10", + "recast": "^0.23.5", + "semver": "^7.6.2", + "util": "^0.12.5", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.12.tgz", + "integrity": "sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@swc/core": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.1.tgz", + "integrity": "sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.17" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.10.1", + "@swc/core-darwin-x64": "1.10.1", + "@swc/core-linux-arm-gnueabihf": "1.10.1", + "@swc/core-linux-arm64-gnu": "1.10.1", + "@swc/core-linux-arm64-musl": "1.10.1", + "@swc/core-linux-x64-gnu": "1.10.1", + "@swc/core-linux-x64-musl": "1.10.1", + "@swc/core-win32-arm64-msvc": "1.10.1", + "@swc/core-win32-ia32-msvc": "1.10.1", + "@swc/core-win32-x64-msvc": "1.10.1" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.1.tgz", + "integrity": "sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.1.tgz", + "integrity": "sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.1.tgz", + "integrity": "sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.1.tgz", + "integrity": "sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.1.tgz", + "integrity": "sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.1.tgz", + "integrity": "sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.1.tgz", + "integrity": "sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.1.tgz", + "integrity": "sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.1.tgz", + "integrity": "sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.1.tgz", + "integrity": "sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.62.9", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.9.tgz", + "integrity": "sha512-lwePd8hNYhyQ4nM/iRQ+Wz2cDtspGeZZHFZmCzHJ7mfKXt+9S301fULiY2IR2byJYY6Z03T427E5PoVfMexHjw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.62.11", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.11.tgz", + "integrity": "sha512-Xb1nw0cYMdtFmwkvH9+y5yYFhXvLRCnXoqlzSw7UkqtCVFq3cG8q+rHZ2Yz1XrC+/ysUaTqbLKJqk95mCgC1oQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.62.9" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/file-saver": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz", + "integrity": "sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", + "dev": true, + "license": "MITClause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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, + "license": "MIT", + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "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, + "license": "MIT" + }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/botw-ist": { + "resolved": "packages/app", + "link": true + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz", + "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "get-intrinsic": "^1.2.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001688", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", + "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.73", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.73.tgz", + "integrity": "sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==", + "dev": true, + "license": "ISC" + }, + "node_modules/embla-carousel": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.5.1.tgz", + "integrity": "sha512-JUb5+FOHobSiWQ2EJNaueCNT/cQU9L6XWBbWmorWPQT9bkbk+fhsuLr8wWrzXKagO3oWszBO7MSx+GfaRk4E6A==", + "license": "MIT" + }, + "node_modules/embla-carousel-autoplay": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/embla-carousel-autoplay/-/embla-carousel-autoplay-8.5.1.tgz", + "integrity": "sha512-FnZklFpePfp8wbj177UwVaGFehgs+ASVcJvYLWTtHuYKURynCc3IdDn2qrn0E5Qpa3g9yeGwCS4p8QkrZmO8xg==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.5.1" + } + }, + "node_modules/embla-carousel-fade": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/embla-carousel-fade/-/embla-carousel-fade-8.5.1.tgz", + "integrity": "sha512-n7vRe2tsTW0vc0Xxtk3APoxhUSXIGh/lGRKYtBJS/SWDeXf9E3qVUst4MfHhwXaHlfu5PLqG3xIEDAr2gwbbNA==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.5.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", + "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", + "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.1.0", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz", + "integrity": "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz", + "integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.0.tgz", + "integrity": "sha512-ArJJTS1lV6lgKH7yEf4EpgNZ7+THl7bsGxxougPYiXRTJ/Fe1j08/TBpV9QsXCIYVfdE/HWG/xLezJ5DOlfBOA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz", + "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", + "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz", + "integrity": "sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz", + "integrity": "sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "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, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.4.tgz", + "integrity": "sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "reflect.getprototypeof": "^1.0.8", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyborg": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.6.0.tgz", + "integrity": "sha512-o5kvLbuTF+o326CMVYpjlaykxqYP9DphFQZ2ZpgrvBouyvOxyEB7oqe8nOLFpiV5VCtz0D3pt8gXQYWpLpBnmA==", + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", + "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mobile-device-detect": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/mobile-device-detect/-/mobile-device-detect-0.4.3.tgz", + "integrity": "sha512-SN9EBE9SoJgkb83kuUVoIp3R9OGYE5dYEnLEz2oLooh0DzgtQ72BJmpNGqrgFvmfE4iLR2CaVJ3RjUcStheVZg==", + "license": "MIT" + }, + "node_modules/monaco-editor": { + "version": "0.52.2", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", + "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/monaco-editor-contrib": { + "resolved": "packages/monaco-editor-contrib", + "link": true + }, + "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, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "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/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-i18next": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.2.0.tgz", + "integrity": "sha512-iJNc8111EaDtVTVMKigvBtPHyrJV+KblWG73cUxqp+WmJCcwkzhWNFXmkAD5pwP2Z4woeDj/oXDdbjDsb3Gutg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", + "integrity": "sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "dunder-proto": "^1.0.0", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.2.0", + "which-builtin-type": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "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-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", + "integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.28.1", + "@rollup/rollup-android-arm64": "4.28.1", + "@rollup/rollup-darwin-arm64": "4.28.1", + "@rollup/rollup-darwin-x64": "4.28.1", + "@rollup/rollup-freebsd-arm64": "4.28.1", + "@rollup/rollup-freebsd-x64": "4.28.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.28.1", + "@rollup/rollup-linux-arm-musleabihf": "4.28.1", + "@rollup/rollup-linux-arm64-gnu": "4.28.1", + "@rollup/rollup-linux-arm64-musl": "4.28.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.28.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.28.1", + "@rollup/rollup-linux-riscv64-gnu": "4.28.1", + "@rollup/rollup-linux-s390x-gnu": "4.28.1", + "@rollup/rollup-linux-x64-gnu": "4.28.1", + "@rollup/rollup-linux-x64-musl": "4.28.1", + "@rollup/rollup-win32-arm64-msvc": "4.28.1", + "@rollup/rollup-win32-ia32-msvc": "4.28.1", + "@rollup/rollup-win32-x64-msvc": "4.28.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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, + "license": "MIT", + "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/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/skybook-item-assets": { + "resolved": "packages/item-assets", + "link": true + }, + "node_modules/skybook-item-system": { + "resolved": "packages/item-system", + "link": true + }, + "node_modules/skybook-localization": { + "resolved": "packages/localization", + "link": true + }, + "node_modules/skybook-runtime-wasm": { + "resolved": "packages/runtime-wasm/pkg", + "link": true + }, + "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, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/storybook": { + "version": "8.4.7", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.4.7.tgz", + "integrity": "sha512-RP/nMJxiWyFc8EVMH5gp20ID032Wvk+Yr3lmKidoegto5Iy+2dVQnUoElZb2zpbVXNHWakGuAkfI0dY1Hfp/vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core": "8.4.7" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabster": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-8.2.0.tgz", + "integrity": "sha512-Gvplk/Yl/12aVFA6FPOqGcq31Qv8hbPfYO0N+6IxrRgRT6eSLsipT6gkZBYjyOwGsp6BD5XlZAuJgupfG/GHoA==", + "license": "MIT", + "dependencies": { + "keyborg": "2.6.0", + "tslib": "^2.3.1" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tosource": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/tosource/-/tosource-2.0.0-alpha.3.tgz", + "integrity": "sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfck": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz", + "integrity": "sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", + "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.0.tgz", + "integrity": "sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.18.0", + "@typescript-eslint/parser": "8.18.0", + "@typescript-eslint/utils": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.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, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-disposable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.4.tgz", + "integrity": "sha512-j83t6AMLWUyb5zwlTDqf6dP9LezM9R0yTbI/b6olmdaGtCKQUe9pgJWV6dRaaQLcozypjIEp4EmZr2DkZGKLSg==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-top-level-await": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.4.4.tgz", + "integrity": "sha512-QyxQbvcMkgt+kDb12m2P8Ed35Sp6nXP+l8ptGrnHV9zgYDUpraO0CPdlqLSeBqvY2DToR52nutDG7mIHuysdiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-virtual": "^3.0.2", + "@swc/core": "^1.7.0", + "uuid": "^10.0.0" + }, + "peerDependencies": { + "vite": ">=2.8" + } + }, + "node_modules/vite-plugin-wasm": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-wasm/-/vite-plugin-wasm-3.3.0.tgz", + "integrity": "sha512-tVhz6w+W9MVsOCHzxo6SSMSswCeIw4HTrXEi6qL3IRzATl83jl09JVO1djBqPSwfjgnpVHNLYcaMbaDX5WB/pg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": "^2 || ^3 || ^4 || ^5" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz", + "integrity": "sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.0", + "is-number-object": "^1.1.0", + "is-string": "^1.1.0", + "is-symbol": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz", + "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workex": { + "resolved": "packages/workex", + "link": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "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 + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.2.tgz", + "integrity": "sha512-8qNdnJVJlHlrKXi50LDqqUNmUbuBjoKLrYQBnoChIbVph7vni+sY+YpvdjXG9YLd/Bxr6scMcR+rm5H3aSqPaw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "packages/app": { + "name": "botw-ist", + "version": "0.0.0", + "dependencies": { + "@fluentui/react-components": "^9.56.8", + "@fluentui/react-icons": "^2.0.270", + "@pistonite/intwc": "0.0.1", + "@pistonite/pure": "^0.0.17", + "@pistonite/pure-react": "^0.0.5", + "@pistonite/skybook-extension-api": "*", + "@tanstack/react-query": "^5.62.11", + "mobile-device-detect": "^0.4.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "reselect": "^5.1.1", + "skybook-localization": "*", + "skybook-runtime-wasm": "*", + "workex": "*", + "zustand": "^5.0.2" + }, + "devDependencies": { + "vite-plugin-top-level-await": "^1.4.4", + "vite-plugin-wasm": "^3.3.0" + } + }, + "packages/extension-api": { + "name": "@pistonite/skybook-extension-api", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@pistonite/pure": "*" + } + }, + "packages/intwc": { + "name": "@pistonite/intwc", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@pistonite/monaco-typescript-contrib": "0.0.1", + "@pistonite/pure": "*", + "monaco-editor-contrib": "0.52.2" + }, + "devDependencies": { + "@catppuccin/palette": "^1.7.1", + "@types/react": "^18.3.16", + "react": "^18.3.1", + "vite": "^5.4.11" + } + }, + "packages/item-assets": { + "name": "skybook-item-assets", + "version": "0.0.0", + "peerDependencies": { + "@griffel/react": "*", + "@types/react": "*", + "react": "*" + } + }, + "packages/item-display": { + "name": "skybook-item-display", + "version": "0.0.0", + "extraneous": true, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@chromatic-com/storybook": "^3.2.3", + "@storybook/addon-essentials": "^8.4.7", + "@storybook/addon-interactions": "^8.4.7", + "@storybook/addon-onboarding": "^8.4.7", + "@storybook/blocks": "^8.4.7", + "@storybook/react": "^8.4.7", + "@storybook/react-vite": "^8.4.7", + "@storybook/test": "^8.4.7", + "prop-types": "^15.8.1", + "storybook": "^8.4.7" + } + }, + "packages/item-slots": { + "name": "skybook-item-slots", + "version": "0.0.0", + "extraneous": true, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "skybook-item-sprites": "*" + }, + "devDependencies": {} + }, + "packages/item-sprites": { + "name": "skybook-item-sprites", + "version": "0.0.0", + "extraneous": true, + "peerDependencies": { + "@griffel/react": "*", + "@types/react": "*", + "react": "*" + } + }, + "packages/item-system": { + "name": "skybook-item-system", + "version": "0.0.0", + "dependencies": { + "@fluentui/react-components": "*", + "@fluentui/react-icons": "*", + "react": "*", + "react-dom": "*", + "skybook-item-assets": "*", + "skybook-localization": "*" + } + }, + "packages/localization": { + "name": "skybook-localization", + "version": "0.0.0", + "dependencies": { + "@pistonite/pure": "*", + "i18next": "^24.2.0", + "react-i18next": "^15.2.0" + } + }, + "packages/monaco-editor-contrib": { + "version": "0.52.2", + "license": "MIT", + "devDependencies": { + "@types/node": "^22.10.2", + "monaco-editor": "0.52.2" + } + }, + "packages/monaco-typescript-contrib": { + "name": "@pistonite/monaco-typescript-contrib", + "version": "0.0.1", + "license": "MIT", + "devDependencies": { + "monaco-editor-contrib": "0.52.2" + } + }, + "packages/runtime-wasm/pkg": { + "name": "skybook-runtime-wasm", + "version": "0.0.0" + }, + "packages/workex": { + "version": "0.0.4" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dcc91ce --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "workspaces": [ + "packages/app", + "packages/extension-api", + "packages/intwc", + "packages/item-assets", + "packages/item-system", + "packages/localization", + "packages/monaco-typescript-contrib", + "packages/monaco-editor-contrib", + "packages/runtime-wasm/pkg", + "packages/workex" + ], + "devDependencies": { + "@eslint/js": "^9.17.0", + "@modyfi/vite-plugin-yaml": "^1.1.0", + "@types/react": "^18.3.16", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.17.0", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.16", + "globals": "^15.13.0", + "prettier": "^3.4.2", + "storybook": "^8.4.7", + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.0", + "vite": "^5.4.11", + "vite-tsconfig-paths": "^5.1.4" + }, + "prettier": { + "tabWidth": 4, + "endOfLine": "auto" + } +} diff --git a/packages/acorn/Cargo.toml b/packages/acorn/Cargo.toml new file mode 100644 index 0000000..23f4c9f --- /dev/null +++ b/packages/acorn/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "skybook-acorn" +version = "0.0.0" +description = "Core of the skybook IST simulator" +edition = "2021" + +[dependencies] +enumset = "1.1.5" +heck = "0.5.0" +serde = { version = "1.0.217", features = ["derive"] } +serde_variant = "0.1.3" +serde_yaml_ng = "0.10.0" diff --git a/packages/acorn/src/command/arg.rs b/packages/acorn/src/command/arg.rs new file mode 100644 index 0000000..35a95ce --- /dev/null +++ b/packages/acorn/src/command/arg.rs @@ -0,0 +1,70 @@ +pub struct StartGameArgs {} + + +pub struct GetItemArgs { + /// Name of the item actor to get + pub actor: String, + + /// Value to use for the item if given. + /// + /// If not given, equipment should receive their default durability + /// (generalLife). Other items should use 1 as the value + pub value: Option, + + pub modifier: Option, + + pub cook_item: Option, +} + +/// uking::CookItem in cookManager.h +pub struct CookItemData { + pub ingredients: Vec, + pub life_recover: f32, + pub effect_time: i32, + pub sell_price: i32, + pub effect_id: CookEffect, + pub effect_level: f32, + pub is_crit: bool +} + +/// uking::CookEffectId in cookManager.h +#[repr(i32)] +pub enum CookEffect { + None = -1, + LifeRecover = 1, + LifeMaxUp = 2, + ResistHot = 4, + ResistCold = 5, + ResistElectric = 6, + AttackUp = 10, + DefenseUp = 11, + Quietness = 12, + // note the name we use internally for skybook is different + // for decomp, it's MovingSpeed + AllSpeed = 13, + GutsRecover = 14, + ExGutsMaxUp = 15, + Fireproof = 16, +} + +/// uking::act::WeaponModifierInfo in actWeapon.h +pub struct WeaponModifierInfo { + pub flags: u32, + pub value: i32 +} + +#[repr(u32)] +pub enum WeaponModifier { + None = 0, + AddPower = 0x1, + AddLife = 0x2, + Critical = 0x4, + LongThrow = 0x8, + SpreadFire = 0x10, + Zoom = 0x20, + RapidFire = 0x40, + SurfMaster = 0x80, + AddGuard = 0x100, + Yellow = 0x80000000, +} + diff --git a/packages/acorn/src/command/core_command.rs b/packages/acorn/src/command/core_command.rs new file mode 100644 index 0000000..f777f9e --- /dev/null +++ b/packages/acorn/src/command/core_command.rs @@ -0,0 +1,11 @@ +use super::arg::{GetItemArgs, StartGameArgs}; + + +pub enum CoreCommand { + /// Start the game (!core-start) + StartGame(StartGameArgs), + /// Add an item to inventory (!core-add) + /// + /// If value is not given, this uses the logic for doGetItem (0x0073A464) + Add(GetItemArgs), +} diff --git a/packages/acorn/src/command/mod.rs b/packages/acorn/src/command/mod.rs new file mode 100644 index 0000000..ecf058e --- /dev/null +++ b/packages/acorn/src/command/mod.rs @@ -0,0 +1,2 @@ +mod arg; +mod core_command; diff --git a/packages/acorn/src/error.rs b/packages/acorn/src/error.rs new file mode 100644 index 0000000..29015dd --- /dev/null +++ b/packages/acorn/src/error.rs @@ -0,0 +1,79 @@ +use crate::{registers::Registers, PageTable}; + + +pub struct Crash { + /// The instruction location that is being + /// executed when the crash happened + pub pc: u64, + + pub registers: Registers, + + pub reason: CrashReason, + + /// If memory dump on crash (:enable memory-dump) is enabled, this will contain the memory + /// snapshot at the time of the crash + pub memory: Option, +} + +pub enum CrashReason { + /// Trying to execute an instruction that is bad/malformed + BadInstruction(u32), + /// Trying to execute an instruction that is recognized, but not + /// supported on the (emulated) hardware + Unsupported(u32), + /// Trying to execute an instruction that is recognized but not implemented + Unimplemented(u32), + /// The program does not have permission to execute the instruction. + /// + /// Suppressed by :enable allow-privileged + PrivilegeRequired(u32), + /// Trying to access an unaligned address + /// + /// Suppressed by :disable memory-alignment, except when + /// the access is across a page boundary, in which case the exception + /// will still occur + Unaligned(MemAccess), + /// Trying to access an address without the proper permissions + /// + /// Suppressed by :disable memory-permissions, in which case + /// all memory addresses have full RWX permissions + PermissionDenied(MemAccess), + /// Trying to read from an unallocated page (for example, a NULL pointer) + /// + /// Suppressed by :disable memory-faults, in which + /// case 0s should be returned by memory reads + PageFault(MemAccess), + /// Error during arithmetic operations + Arithmetic(ArithmeticError), +} + +pub enum ArithmeticError { + /// Integer division by zero + /// + /// Suppressed by :disable divide-by-zero + DivideByZero, + /// Integer Overflow + /// + /// Disabled by default. Enable with :enable integer-bounds + Overflow, + /// Integer Underflow + /// + /// Disabled by default. Enable with :enable integer-bounds + Underflow, +} + +/// Information for accessing memory +pub struct MemAccess { + pub access_type: MemAccessType, + pub addr: u64, + pub bytes: u32, +} + +pub enum MemAccessType { + /// Reading data from the memory + Read, + /// Writing data to the memory + Write, + /// Reading instruction from memory + Execute, +} diff --git a/packages/acorn/src/features.rs b/packages/acorn/src/features.rs new file mode 100644 index 0000000..4c9458d --- /dev/null +++ b/packages/acorn/src/features.rs @@ -0,0 +1,66 @@ +use enumset::{EnumSet, EnumSetType}; +use heck::AsKebabCase; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Hash, EnumSetType, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum CoreFeature { + /// Allow privileged instructions (disabled by default) + AllowPrivileged, + + /// Enforce aligned memory access within a page + MemoryAlignment, + + /// Enforce memory access permissions + MemoryPermissions, + + /// Fault when reading unallocated memory + MemoryFaults, + + /// Detect integer division by zero + DivideByZero, + + /// Detect wrapping operations on signed and unsigned integers (disabled by default) + IntegerBounds, + + /// Dump all allocated memory just before crash + MemoryDump, +} + +impl std::fmt::Display for CoreFeature { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", serde_variant::to_variant_name(self).unwrap()) + } +} + +impl CoreFeature { + /// Convert from a string, returns None if the feature is not recognized + pub fn from_str(s: &str) -> Option { + serde_yaml_ng::from_str(s).ok() + } +} + +/// Get the default feature sets +pub fn default_features() -> EnumSet { + CoreFeature::MemoryAlignment + | CoreFeature::MemoryPermissions + | CoreFeature::MemoryFaults + | CoreFeature::DivideByZero +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_to_string() { + assert_eq!("memory-alignment", CoreFeature::MemoryAlignment.to_string()); + assert_eq!("divide-by-zero", CoreFeature::DivideByZero.to_string()); + } + #[test] + fn test_from_string() { + assert_eq!(CoreFeature::from_str("memory-alignment"), Some(CoreFeature::MemoryAlignment)); + assert_eq!(CoreFeature::from_str("divide-by-zero"), Some(CoreFeature::DivideByZero)); + assert_eq!(CoreFeature::from_str("memory"), None); + } +} diff --git a/packages/acorn/src/lib.rs b/packages/acorn/src/lib.rs new file mode 100644 index 0000000..994822a --- /dev/null +++ b/packages/acorn/src/lib.rs @@ -0,0 +1,83 @@ +use std::{borrow::{Borrow, BorrowMut}, collections::HashMap, sync::Arc}; + +mod command; +mod error; +mod registers; +mod features; +mod util; +mod processor; + +/// A read-only snapshot of memory pages at a certain +/// simulation step +pub struct MemorySnapshot { +} + +const PAGE_SIZE: usize = 4096; + +#[derive(Debug, Clone)] +pub struct Page { + data: [u8; PAGE_SIZE], + // other metadata, like permission., etc +} + +impl Page { + pub fn new() -> Self { + Self { + data: [0; PAGE_SIZE], + // other ... + } + } +} + +#[derive(Debug, Clone)] +pub struct PageTable { + pages: HashMap>, +} + +impl PageTable { + /// Get read access to page at addr + /// + /// Returns None if the page is not allocated, i.e. a page fault + pub fn read(&self, addr: u64) -> Option<&Page> { + self.pages.get(&addr).map(|page| page.as_ref()) + } + + /// Get write access to page at addr + /// + /// Allocates the page if it's not allocated. Clones the page if it's shared + pub fn write(&mut self, addr: u64) -> &mut Page { + let arc_page = self.pages.entry(addr).or_insert_with(|| Arc::new(Page::new())); + Arc::make_mut(arc_page) + } +} + + +// pub struct Core<'m> { +// registers: Registers, +// // having lifetime here is OK. +// // Core is not meant to be a short-lived object, +// // only to associate the CPU functions with the memory +// memory: &'m mut PageTable, +// } +// +// impl<'m> Core<'m> { +// pub fn attach(memory: &'m mut PageTable) -> Self { +// Self { +// registers: Registers::new(), +// memory, +// } +// } +// +// pub fn init_memory(&mut self, executable: Executable) -> SingletonTable { +// // load the executable, call ctors, etc... +// // executable could be the partial one we provide +// // or the full one user provides +// // +// // Returns a table of proxy to singletons, like PMDM, +// // to provide read-only access to the memory +// } +// +// pub fn execute_command(&mut self, core_command: CoreCommand) { +// // ... +// } +// } diff --git a/packages/acorn/src/processor.rs b/packages/acorn/src/processor.rs new file mode 100644 index 0000000..49ca573 --- /dev/null +++ b/packages/acorn/src/processor.rs @@ -0,0 +1,20 @@ +use crate::registers::Registers; + + +pub struct Processor { + pub registers: Registers, + pub pc: u64, + pub flags: Flags, +} + +/// Condition flags +pub struct Flags { + /// Negative + pub n: bool, + /// Zero + pub z: bool, + /// Carry + pub c: bool, + /// Overflow + pub v: bool, +} diff --git a/packages/acorn/src/registers.rs b/packages/acorn/src/registers.rs new file mode 100644 index 0000000..05a82b7 --- /dev/null +++ b/packages/acorn/src/registers.rs @@ -0,0 +1,29 @@ +#[derive(Debug, Clone, PartialEq)] +// https://developer.arm.com/documentation/dui0801/l/Overview-of-AArch64-state/Registers-in-AArch64-state +#[allow(dead_code)] +pub struct Registers { + // 31 general-purpose registers (called X0-X30 in code) + // X30 is used as the link register (LR) + pub x: [i64; 31], + // 32 floating-point registers (called S0-S31 in code) - 128 bits each + pub s: [f64; 32], + // 4 stack pointer registers + // https://developer.arm.com/documentation/dui0801/l/Overview-of-AArch64-state/Stack-Pointer-register?lang=en + // sp_el0 is the classic "SP" register + // The other 3 are stack pointers for each of the 3 exception levels + // This is why the exception link/program status registers go from 1-3 rather than 0-2 + pub sp_el0: u64, + pub sp_el1: u64, + pub sp_el2: u64, + pub sp_el3: u64, + // 3 exception link registers + pub elr_el1: i64, + pub elr_el2: i64, + pub elr_el3: i64, + // 3 saved program status registers (these are 32 bits) + pub spsr_el1: i32, + pub spsr_el2: i32, + pub spsr_el3: i32, + // Floating point status control register + pub fpscr: i32, +} diff --git a/packages/acorn/src/util.rs b/packages/acorn/src/util.rs new file mode 100644 index 0000000..477b45e --- /dev/null +++ b/packages/acorn/src/util.rs @@ -0,0 +1,5 @@ +use enumset::{EnumSet, EnumSetType}; + +pub struct FlagStack { + stack: Vec>, +} diff --git a/packages/actor-sys/Cargo.toml b/packages/actor-sys/Cargo.toml new file mode 100644 index 0000000..d8b758b --- /dev/null +++ b/packages/actor-sys/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "actor-sys" +private = true +version = "0.0.0" +edition = "2021" +description = "Binding for actor parameters" + +[dependencies] + + +[[bin]] # Script to generate the source files +name = "actor-sys-generate" +path = "generate.rs" + +# The features are auto-generated!!! +[features] diff --git a/sim/core/.gitkeep b/packages/actor-sys/generate.rs similarity index 100% rename from sim/core/.gitkeep rename to packages/actor-sys/generate.rs diff --git a/app/src/sim/src/lib.rs b/packages/actor-sys/src/lib.rs similarity index 100% rename from app/src/sim/src/lib.rs rename to packages/actor-sys/src/lib.rs diff --git a/app/.gitignore b/packages/app/.gitignore similarity index 100% rename from app/.gitignore rename to packages/app/.gitignore diff --git a/app/README.md b/packages/app/README.md similarity index 100% rename from app/README.md rename to packages/app/README.md diff --git a/app/Taskfile.yml b/packages/app/Taskfile.yml similarity index 88% rename from app/Taskfile.yml rename to packages/app/Taskfile.yml index 5f05bce..77e1498 100644 --- a/app/Taskfile.yml +++ b/packages/app/Taskfile.yml @@ -6,6 +6,10 @@ tasks: cmds: - npx vite --host + runtime-workex: + cmds: + - workex -p runtime src/runtime/protocol.ts --lib-path workex --no-lib + build: desc: Build production bundle cmds: diff --git a/app/eslint.config.js b/packages/app/eslint.config.js similarity index 100% rename from app/eslint.config.js rename to packages/app/eslint.config.js diff --git a/packages/app/icon.ts b/packages/app/icon.ts new file mode 100644 index 0000000..9caeaac --- /dev/null +++ b/packages/app/icon.ts @@ -0,0 +1,95 @@ +scale(1) +unit(1) + +const color_core1 = "#F0C83D83"; +const color_core2 = "#FE8F0088"; +const color_core3 = "red"; +const color_shell1 = "#AD8867"; +const color_shell2 = "#5C4D48"; +const color_shell3 = "#E7DED5"; +const color_light = "#73FBFD"; + +function render_core(t: Point) { + const pillar = point(0, 0, 0).sized(14, 6, 6); + const pillar2 = pillar.translated("y", 8).union(pillar); + const pillar4 = pillar2.translated("z", 8).union(pillar2); + const pillar_cut = point(0, 3, 3).sized(14, 8, 8); + const side_cut = point(3, 0, 3).sized(8, 14, 8); + const top_cut = point(3, 3, 0).sized(8, 8, 14); + + const corner = point(0,0,0).sized(2,2,2); + const corner2 = corner.translated("x", 12).union(corner); + const corner4 = corner2.translated("y", 12).union(corner2); + const corner8 = corner4.translated("z", 12).union(corner4); + + const core = point(1,1,1).sized(12,12,12); + const core_in = point(2,2,2).sized(10,10,10); + const core_in2 = point(3,3,3).sized(8,8,8); + + const center_pillar_out = point(0, 5, 5).sized(14, 4, 4); + const center_pillar_in = point(0, 6, 6).sized(14, 2, 2); + + center_pillar_out + .difference(center_pillar_in) + .difference(core) + .translated(t) + .render(color_shell3); + + center_pillar_in + .difference(core) + .translated(t) + .render(color_light) + + pillar4 + .difference(corner8) + .difference(pillar_cut) + .difference(side_cut) + .difference(top_cut) + .difference(core) + .translated(t) + .render(color_shell2); + + core + .difference(corner8) + .translated(t) + .render(color_core1) + + core_in.translated(t).render(color_core2) + core_in2.translated(t).render(color_core3) + + core.intersection(corner8) + .translated(t) + .render(color_shell2) +} + +function render_ring(x: number, width: number) { + const center_cut = point(0, 1, 1).sized(14, 16, 16); + const middle_ring = point(x, 0, 0).sized(width, 18, 18); + + middle_ring + .difference(center_cut) + .render(color_light) +} + +function render_hring() { + const center_cut = point(1,1,1).sized(16,18,18); + const ring = point(0, 0, 7).sized(18,20,3); + const ring2 = point(0, 0, 8).sized(18,20,1); + + ring + .difference(center_cut) + //.difference(ring2) + .translated(-1, 0, 0) + .render(color_shell1) + + // ring2 + // .difference(center_cut) + // .translated(-1, 0, 0) + // .render(color_shell2) +} + +render_core(point(0,2,2)) +//render_ring(2, 1) +render_ring(6, 2) +//render_ring(11, 1) +render_hring() diff --git a/packages/app/index.html b/packages/app/index.html new file mode 100644 index 0000000..6986c54 --- /dev/null +++ b/packages/app/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + IST Simulator + + + +
+ + + diff --git a/packages/app/package.json b/packages/app/package.json new file mode 100644 index 0000000..d432175 --- /dev/null +++ b/packages/app/package.json @@ -0,0 +1,37 @@ +{ + "name": "botw-ist", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@fluentui/react-components": "^9.56.8", + "@fluentui/react-icons": "^2.0.270", + "@pistonite/intwc": "0.0.1", + "@pistonite/pure": "^0.0.17", + "@pistonite/pure-react": "^0.0.5", + "@pistonite/skybook-extension-api": "*", + "@tanstack/react-query": "^5.62.11", + "mobile-device-detect": "^0.4.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "reselect": "^5.1.1", + "skybook-localization": "*", + "skybook-runtime-wasm": "*", + "workex": "*", + "zustand": "^5.0.2" + }, + "devDependencies": { + "vite-plugin-top-level-await": "^1.4.4", + "vite-plugin-wasm": "^3.3.0" + }, + "prettier": { + "tabWidth": 4, + "endOfLine": "auto" + } +} diff --git a/packages/app/public/CNAME b/packages/app/public/CNAME new file mode 100644 index 0000000..a2e8f8f --- /dev/null +++ b/packages/app/public/CNAME @@ -0,0 +1 @@ +tspoc.pistonite.dev diff --git a/packages/app/public/icon.svg b/packages/app/public/icon.svg new file mode 100644 index 0000000..025a4b4 --- /dev/null +++ b/packages/app/public/icon.svg @@ -0,0 +1 @@ + diff --git a/packages/app/public/manifest.json b/packages/app/public/manifest.json new file mode 100644 index 0000000..c1b20fa --- /dev/null +++ b/packages/app/public/manifest.json @@ -0,0 +1,7 @@ +{ + "short_name": "Skybook", + "name": "Skybook", + "background_color.todo": "", + "display": "fullscreen", + "start_url": "/" +} diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx new file mode 100644 index 0000000..8dd8f65 --- /dev/null +++ b/packages/app/src/App.tsx @@ -0,0 +1,57 @@ + +import { makeStyles } from "@fluentui/react-components" +import { SideToolbar } from "./SideToolbar"; +import { useIsShowingExtensionPanel } from "./application/extensionStore"; +import { ExtensionPanel } from "ui/ExtensionPanel"; +import { useNarrow } from "pure-contrib/narrow"; +import { ResizeLayout } from "ui/components/ResizeLayout"; +import { useUIStore } from "ui/store"; +import { isLessProductive } from "ui/platform"; + +const useStyles = makeStyles({ + root: { + width: "100vw", + height: "100vh", + }, + side: { + width: "100%", + height: "100%", + display: "flex", + flexDirection: "column", + } +}) + +function App() { + const narrow = useNarrow(); + const styles = useStyles(); + + const showExtensionPanel = useIsShowingExtensionPanel(); + + const extensionPanelPercentage = useUIStore(state => state.extensionPanelPercentage); + const setExtensionPanelPercentage = useUIStore(state => state.setExtensionPanelPercentage); + + return ( + +
+ + { showExtensionPanel && } +
+
+ main +
+
+ ); + +} + +export default App diff --git a/packages/app/src/ExtensionWrapper.tsx b/packages/app/src/ExtensionWrapper.tsx new file mode 100644 index 0000000..45aec56 --- /dev/null +++ b/packages/app/src/ExtensionWrapper.tsx @@ -0,0 +1,7 @@ +import { Extension } from "@pistonite/skybook-extension-api" + +export type ExtensionComponentProps = { + extClient: Extension +} + +export type ExtensionComponent = React.ComponentType diff --git a/packages/app/src/SideToolbar.tsx b/packages/app/src/SideToolbar.tsx new file mode 100644 index 0000000..c6a6c97 --- /dev/null +++ b/packages/app/src/SideToolbar.tsx @@ -0,0 +1,38 @@ +import { Button, Card, CardPreview, makeStyles, tokens } from "@fluentui/react-components"; +import { useIsShowingExtensionPanel } from "application/extensionStore"; +import { ExtensionOpenButton } from "ui/ExtensionOpenButton"; +import icon from "./icon.svg"; +import { BookQuestionMark20Regular, Globe20Regular, Settings20Regular } from "@fluentui/react-icons"; + +const useStyles = makeStyles({ + container: { + backgroundColor: tokens.colorNeutralBackground2, + display: "flex", + flexDirection: "row", + } +}); + +export const SideToolbar: React.FC = () => { + const styles = useStyles(); + const showingExtensionPanel = useIsShowingExtensionPanel(); + return ( +
+ + + v4.0.0 + + + +
+ ); +} diff --git a/packages/app/src/application/ApplicationProvider.tsx b/packages/app/src/application/ApplicationProvider.tsx new file mode 100644 index 0000000..547576a --- /dev/null +++ b/packages/app/src/application/ApplicationProvider.tsx @@ -0,0 +1,13 @@ +import { PropsWithChildren } from "react"; +import { Application } from "@pistonite/skybook-extension-api"; + +import { ApplicationContext } from "./useApplication.ts"; + + +export const ApplicationProvider: React.FC> = ({app, children}) => { + return ( + + {children} + + ); +} diff --git a/packages/app/src/application/api.ts b/packages/app/src/application/api.ts new file mode 100644 index 0000000..246bcb9 --- /dev/null +++ b/packages/app/src/application/api.ts @@ -0,0 +1,22 @@ +import { Application } from "@pistonite/skybook-extension-api"; +import { useApplicationStore } from "./store"; +import { debounce } from "@pistonite/pure/sync"; + +const setScript = debounce({ + fn: (script: string) => { + useApplicationStore.setState({script}); + }, + interval: 200, +}); + +export class ApplicationApi implements Application { + public async getScript() { + return {val: useApplicationStore.getState().script}; + } + public async setScript(script: string) { + // await setScript(script); + // return {}; + useApplicationStore.setState({script}); + return {}; + } +} diff --git a/packages/app/src/application/extensionManager.ts b/packages/app/src/application/extensionManager.ts new file mode 100644 index 0000000..42e0ca7 --- /dev/null +++ b/packages/app/src/application/extensionManager.ts @@ -0,0 +1,46 @@ +import { addDarkSubscriber, addLocaleSubscriber } from "@pistonite/pure/pref"; +import { Extension } from "@pistonite/skybook-extension-api"; +import { useApplicationStore } from "./store"; + + +/** Running instances of extensions */ +const instances: Extension[] = []; + +export const initExtensionManager = () => { + const store = useApplicationStore; + store.subscribe((curr, prev) => { + if (prev.script !== curr.script) { + instances.forEach((x) => { + void x.onScriptChanged(curr.script); + }); + } + }); +} + +/** + * Registers an extension as running and connect it to the app. + * + * Returns a function to disconnect the extension from the app. + */ +export const connectExtensionToApp = (extension: Extension): () => void => { + const unsubscribeDark = addDarkSubscriber((x) => { + void extension.onDarkModeChanged(x); + }, true); + const unsubscribeLocale = addLocaleSubscriber((x) => { + void extension.onLocaleChanged(x); + }, true); + void extension.onScriptChanged(useApplicationStore.getState().script); + instances.push(extension); + return () => { + const index = instances.indexOf(extension); + if (index >= 0) { + instances.splice(index, 1); + } + unsubscribeLocale(); + unsubscribeDark(); + } +} + +export const openExtensionPopup = (id: string) => { + console.error("Not implemented", id); +} diff --git a/packages/app/src/application/extensionStore.ts b/packages/app/src/application/extensionStore.ts new file mode 100644 index 0000000..a32564a --- /dev/null +++ b/packages/app/src/application/extensionStore.ts @@ -0,0 +1,203 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { openExtensionPopup } from "./extensionManager"; +import { createSelector } from "reselect"; +import { isLessProductive } from "ui/platform"; + +export const ExtensionIds = ["editor", "stub1", "stub2"] as const; +// Use the sort index to display the extensions in a deterministic order +const ExtensionIdToSortIndex: Record = (() => { + const result: Record = {}; + ExtensionIds.forEach((id, index) => { + result[id] = index; + }); + return result; +})(); + +export type ExtensionStore = { + /** + * Ids of the extensions in the primary slot + */ + primaryIds: string[]; + + /** + * Ids of the extensions in the secondary slot + */ + secondaryIds: string[]; + + currentPrimary: string; + + currentSecondary: string; + + /** + * Set the open preference for the extension with the id + */ + // setExtensionPreference(id: string, preference: "primary" | "secondary" | "none"): void; + + /** + * Open an extension in the primary or secondary slot, optionally + * update the open mode for the extension for the future + */ + open: (id: string, slot: "primary" | "secondary", updateOpenMode?: boolean) => void; + + /** + * Update the open mode for the extension with the id + */ + updateOpenMode: (id: string, openMode: ExtensionOpenMode) => void; + + /** + * Close the primary extension window + */ + closePrimary: () => void; + + /** + * Close the secondary extension window + */ + closeSecondary: () => void; +} + +export type ExtensionOpenMode = "primary" | "secondary" | "popout"; + +export const useExtensionStore = create()((set) => ({ + primaryIds: ["editor", "stub2"], + secondaryIds: ["stub1"], + currentPrimary: "editor", + currentSecondary: "stub1", + + open: (id: string, slot: "primary" | "secondary", updateOpenMode = false) => { + set(({primaryIds, secondaryIds}) => { + const newState: Partial = { }; + if (slot === "primary") { + newState.currentPrimary = id; + if (updateOpenMode) { + if (secondaryIds.includes(id)) { + newState.secondaryIds = secondaryIds.filter((i) => i !== id); + } + if (!primaryIds.includes(id)) { + newState.primaryIds = [...primaryIds, id]; + } + } + } else { + newState.currentSecondary = id; + if (updateOpenMode) { + if (primaryIds.includes(id)) { + newState.primaryIds = primaryIds.filter((i) => i !== id); + } + if (!secondaryIds.includes(id)) { + newState.secondaryIds = [...secondaryIds, id]; + } + } + } + return newState; + }); + }, + + updateOpenMode: (id: string, openMode: ExtensionOpenMode) => { + set(({primaryIds, secondaryIds}) => { + const newState: Partial = { }; + if (openMode === "primary") { + if (secondaryIds.includes(id)) { + newState.secondaryIds = secondaryIds.filter((i) => i !== id); + } + if (!primaryIds.includes(id)) { + newState.primaryIds = [...primaryIds, id]; + } + } else if (openMode === "secondary") { + newState.currentSecondary = id; + if (primaryIds.includes(id)) { + newState.primaryIds = primaryIds.filter((i) => i !== id); + } + if (!secondaryIds.includes(id)) { + newState.secondaryIds = [...secondaryIds, id]; + } + } else { + if (primaryIds.includes(id)) { + newState.primaryIds = primaryIds.filter((i) => i !== id); + } + if (secondaryIds.includes(id)) { + newState.secondaryIds = secondaryIds.filter((i) => i !== id); + } + } + return newState; + }); + }, + + closePrimary: () => { + set({currentPrimary: ""}); + }, + + closeSecondary: () => { + set({currentSecondary: ""}); + } + +})); +// ,{ +// name: "Skybook.Extensions", +// version: 1, +// })); +// + +export const useAllExtensionIds = () => { + return ExtensionIds; +} + +const getAllNonPopoutExtensionIds = createSelector([ + (state: ExtensionStore) => state.primaryIds, + (state: ExtensionStore) => state.secondaryIds +], (p, s) => { + return sortExtensionIds([...p, ...s]); + }); +export const useAllNonPopoutExtensionIds = () => { + return useExtensionStore(getAllNonPopoutExtensionIds); +} + +const getPrimaryExtensionIds = createSelector([ + (state: ExtensionStore) => state.primaryIds +], (p) => { + return sortExtensionIds([...p]); +}); +export const usePrimaryExtensionIds = () => { + return useExtensionStore(getPrimaryExtensionIds); +} + +const getSecondaryExtensionIds = createSelector([ + (state: ExtensionStore) => state.secondaryIds +], (s) => { + return sortExtensionIds([...s]); +}); +export const useSecondaryExtensionIds = () => { + return useExtensionStore(getSecondaryExtensionIds); +} + +const sortExtensionIds = (ids: string[]): string[] => { + // toSorted + return ids.sort((a, b) => { + const aIndex = a in ExtensionIdToSortIndex ? ExtensionIdToSortIndex[a] : 9999; + const bIndex = b in ExtensionIdToSortIndex ? ExtensionIdToSortIndex[b] : 9999; + return aIndex - bIndex; + }); +} + +export const useCurrentPrimaryExtensionId = () => { + return useExtensionStore((state) => state.currentPrimary); +} + +const getSecondaryExtensionId = createSelector([ + (state: ExtensionStore) => state.currentSecondary, +], (id) => { + // don't show secondary extension if on less productive platform + return isLessProductive ? "" : id; +}); +export const useCurrentSecondaryExtensionId = () => { + return useExtensionStore(getSecondaryExtensionId); +} + +const getIsShowingSecondaryExtension = createSelector([ + (state: ExtensionStore) => state.currentPrimary, + getSecondaryExtensionId +], (p, s) => { + return p || s; +}); +export const useIsShowingExtensionPanel = () => { + return useExtensionStore(getIsShowingSecondaryExtension); +} diff --git a/packages/app/src/application/store.ts b/packages/app/src/application/store.ts new file mode 100644 index 0000000..04fa6b9 --- /dev/null +++ b/packages/app/src/application/store.ts @@ -0,0 +1,12 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; + +export type ApplicationStore = { + script: string; +} + +export const useApplicationStore = create()(persist((set)=>({ + script: "", +}), { + name: "Skybook.Application", + })) diff --git a/packages/app/src/application/useApplication.ts b/packages/app/src/application/useApplication.ts new file mode 100644 index 0000000..f5a966a --- /dev/null +++ b/packages/app/src/application/useApplication.ts @@ -0,0 +1,8 @@ +import { createContext, useContext } from "react"; +import { Application } from "@pistonite/skybook-extension-api"; + +export const ApplicationContext = createContext({} as unknown as Application); + +export const useApplication = () => { + return useContext(ApplicationContext); +} diff --git a/packages/app/src/extensions/ExtensionWindow.tsx b/packages/app/src/extensions/ExtensionWindow.tsx new file mode 100644 index 0000000..79479c0 --- /dev/null +++ b/packages/app/src/extensions/ExtensionWindow.tsx @@ -0,0 +1,78 @@ +import { Dropdown, makeStyles, Option } from "@fluentui/react-components"; +import { useQuery } from "@tanstack/react-query"; + +import { useUITranslation } from "skybook-localization"; + +import { getExtensionComponent } from "./registry"; +import { connectExtensionToApp } from "application/extensionManager"; + +export type ExtensionWindowProps = { + primary: boolean; + ids: string[]; + currentId: string; + onSelect: (id: string) => void; +} + +const useStyles = makeStyles({ + container: { + display: "flex", + flexDirection: "column", + height: "100%", + }, + extension: { + flex: 1, + } +}); + +export const ExtensionWindow: React.FC = ({ primary, ids, currentId, onSelect }) => { + const t = useUITranslation(); + const styles = useStyles(); + return ( +
+ { + console.log(optionValue) + }} + > + { + ids.map((id, i) => ( + + )) + } + + { + ids.map((id, i) => ( +
+ +
+ )) + } +
+ ); + +} + + +export type ExtensionWrapperProps = { + id: string; +} + +export const ExtensionWrapper: React.FC = ({ id }) => { + const {isPending, data: ExtComp } = useQuery({ + queryKey: ["extension", id], + queryFn: () => { + return getExtensionComponent(id); + }, + }); + if (isPending || !ExtComp) { + return
Loading...
+ } + return ; +} diff --git a/packages/app/src/extensions/Stub1.tsx b/packages/app/src/extensions/Stub1.tsx new file mode 100644 index 0000000..02e6792 --- /dev/null +++ b/packages/app/src/extensions/Stub1.tsx @@ -0,0 +1,2 @@ + +export const makeStub = (id: number) => () =>
Stub {id}
; diff --git a/packages/app/src/extensions/Wrapper.tsx b/packages/app/src/extensions/Wrapper.tsx new file mode 100644 index 0000000..bfea5f2 --- /dev/null +++ b/packages/app/src/extensions/Wrapper.tsx @@ -0,0 +1,19 @@ +import { useQuery } from "@tanstack/react-query"; +import { getExtensionComponent } from "./registry"; + +export type ExtensionWrapperProps = { + id: string; +} + +export const ExtensionWrapper: React.FC = ({ id }) => { + const {isPending, data: ExtComp } = useQuery({ + queryKey: ["extension", id], + queryFn: () => { + return getExtensionComponent(id); + }, + }); + if (isPending || !ExtComp) { + return
Loading...
+ } + return ; +} diff --git a/packages/app/src/extensions/editor/EditorComponent.tsx b/packages/app/src/extensions/editor/EditorComponent.tsx new file mode 100644 index 0000000..4a2b4ca --- /dev/null +++ b/packages/app/src/extensions/editor/EditorComponent.tsx @@ -0,0 +1,40 @@ +// import { useEffect } from "react"; + +import type { ExtensionComponentProps } from "../types.ts" +import { initLanguage } from "./Language.ts" +import { CodeEditor } from "@pistonite/intwc"; +import { EditorExtension } from "./editor.ts"; +import { useApplication } from "application/useApplication.ts"; + + +const FILE = "script.skyb"; + + +export const EditorComponent: React.FC = ({ + standalone, connect +}) => { + const app = useApplication(); + initLanguage(); + // useEffect(() => { + // }, []); + return ( + { + const unsubscribeEditor = editor.subscribe((filename) => { + if (filename !== FILE) { + return; + } + void app.setScript(editor.getFileContent(FILE)); + }); + const instance = new EditorExtension(FILE, standalone, editor); + const disconnect = connect(instance); + console.log("EditorComponent: onCreated"); + return () => { + unsubscribeEditor(); + disconnect(); + }; + }} + /> + ); +} diff --git a/packages/app/src/extensions/editor/Language.ts b/packages/app/src/extensions/editor/Language.ts new file mode 100644 index 0000000..6b360b4 --- /dev/null +++ b/packages/app/src/extensions/editor/Language.ts @@ -0,0 +1,79 @@ +import { initCodeEditor, LanguageConfiguration, LanguageTokenizer } from "@pistonite/intwc"; + +let initialized = false; + +export const initLanguage = () => { + if (initialized) { + return; + } + initialized = true; + initCodeEditor({ + language: { + custom: [ + { + getId: () => "skyb", + getExtensions: () => [".skyb"], + getTokenizer: () => language, + getConfiguration: () => configuration, + } + ] + } + }); +} + +export const configuration: LanguageConfiguration = { + comments: { + lineComment: "#", + }, + + brackets: [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["<", ">"], + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' }, + { open: '"', close: '"', notIn: ['string'] }, + ], +} + +export const language: LanguageTokenizer = { + defaultToken: 'invalid', + tokenPostfix: '.skyb', + + commands: [ + "init" + ], + supercommands: [], + annotations: [], + keywords: [], + + word: /[_a-zA-Z][-0-9a-zA-Z_]*/, + + tokenizer: { + root: [ + [/\s+/, "white"], + [/\/\/.*$/, "comment"], + [/#.*$/, "comment"], + [/[{}()[\]]/, "@brackets"], + [/[=:,;]/, "delimiter"], + [/(\d(_?\d)*)|(0x[\da-fA-F](_?[\da-fA-F])*)/, "number"], + [/<@word>/, "string.item.literal"], + [/"@word"/, "string.item.quoted"], + [/!@word/, "function.command.super"], + [/:@word/, "keyword.annotation"], + [/(true|false)/, "constant.language.boolean"], + [/@word/, { + cases: { + "@keywords": "keyword", + "@commands": "function.command", + "@default": "string.item", + } + }] + ] + } +} diff --git a/packages/app/src/extensions/editor/editor.ts b/packages/app/src/extensions/editor/editor.ts new file mode 100644 index 0000000..b1622cb --- /dev/null +++ b/packages/app/src/extensions/editor/editor.ts @@ -0,0 +1,33 @@ +import { CodeEditorApi } from "@pistonite/intwc"; +import { setDark, setLocale } from "@pistonite/pure/pref"; +import { Extension } from "@pistonite/skybook-extension-api"; +import { WorkexPromise } from "workex"; + + +export class EditorExtension implements Extension { + + constructor( + private scriptFile: string, + private standalone: boolean, private editor: CodeEditorApi) { + } + public async onDarkModeChanged(dark: boolean): WorkexPromise { + if (this.standalone) { + setDark(dark); + } + return {}; + } + public async onLocaleChanged(locale: string): WorkexPromise { + if (this.standalone) { + setLocale(locale); + } + return {}; + } + public async onScriptChanged(script: string): WorkexPromise { + if (!this.editor.getFiles().includes(this.scriptFile)) { + this.editor.openFile(this.scriptFile, script, "skyb"); + } else { + this.editor.setFileContent(this.scriptFile, script); + } + return {}; + } +} diff --git a/packages/app/src/extensions/registry.ts b/packages/app/src/extensions/registry.ts new file mode 100644 index 0000000..7794ea5 --- /dev/null +++ b/packages/app/src/extensions/registry.ts @@ -0,0 +1,17 @@ +import { makeStub } from "./Stub1.tsx"; +import type { ExtensionComponentProps } from "./types.ts"; + + +export const getExtensionComponent = async (id: string): Promise | undefined> => { + switch (id) { + case "editor": + return (await import("./editor/EditorComponent.tsx")).EditorComponent; + case "stub1": + return makeStub(1); + case "stub2": + return makeStub(2); + + } + + return undefined; +} diff --git a/packages/app/src/extensions/types.ts b/packages/app/src/extensions/types.ts new file mode 100644 index 0000000..3dfd5f0 --- /dev/null +++ b/packages/app/src/extensions/types.ts @@ -0,0 +1,23 @@ +import { Extension } from "@pistonite/skybook-extension-api" + +export type ExtensionComponentProps = { + /** + * If the extension is loaded as part of the app, + * or in its standalone window + */ + standalone: boolean; + + /** + * Callback to connect the extension to the app, once it's ready + */ + connect: (ext: Extension) => () => void; +} + +export type ExtensionComponent = React.ComponentType + +export type ExtensionMetadata = { + //type: "builtin"; + id: string; + + render: React.ComponentType; +} diff --git a/packages/app/src/icon.svg b/packages/app/src/icon.svg new file mode 100644 index 0000000..774d16a --- /dev/null +++ b/packages/app/src/icon.svg @@ -0,0 +1 @@ + diff --git a/packages/app/src/main.tsx b/packages/app/src/main.tsx new file mode 100644 index 0000000..db87b35 --- /dev/null +++ b/packages/app/src/main.tsx @@ -0,0 +1,74 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.tsx' +import { ThemeProvider } from './theme/ThemeProvider.tsx' +import { initDark } from '@pistonite/pure/pref' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { initI18n } from 'skybook-localization' +import { initExtensionManager } from './application/extensionManager.ts' +import { initRuntime } from 'runtime/init.ts' +import { ApplicationApi } from 'application/api.ts' +import { ApplicationProvider } from 'application/ApplicationProvider.tsx' +import { initNarrow } from 'pure-contrib/narrow.ts' +import { isLessProductive } from 'ui/platform.ts' + +async function boot() { + const root = document.getElementById('-root-') as HTMLDivElement; + if (isLessProductive) { + // window.setStatus + // await new Promise((resolve) => { + // const button = document.createElement('button'); + // button.innerText = 'fullscreen' + window.innerWidth; + // button.onclick = async () => { + // // document.body.style.height = 'calc ( 100vh + 1px )'; + // // document.body.style.overflow = 'visible'; + // // root.style.height = 'calc ( 100vh + 1px )'; + // // window.scrollTo(0, 100); + // await document.body.requestFullscreen({ + // navigationUI: "hide"}); + // resolve(); + // }; + // root.appendChild(button); + // }); + initNarrow({ + threshold: 800, + override: (narrow) => { + if (window.innerWidth < window.innerHeight) { + return true; + } + if (narrow && window.innerHeight < window.innerWidth) { + return false; + } + return narrow; + }, + }); + } else { + initNarrow({ + threshold: 800, + }); + } + initDark({ + persist: false, + }); + await initI18n(); + initExtensionManager(); + const queryClient = new QueryClient(); + + const runtime = await initRuntime(); + + const app = new ApplicationApi(); + + + createRoot(root).render( + + + + + + + + + , + ) +} +void boot() diff --git a/packages/app/src/pure-contrib/narrow.ts b/packages/app/src/pure-contrib/narrow.ts new file mode 100644 index 0000000..0e4eca4 --- /dev/null +++ b/packages/app/src/pure-contrib/narrow.ts @@ -0,0 +1,71 @@ +import { cell } from "@pistonite/pure/sync"; +import { useSyncExternalStore } from "react"; + +const narrow = cell({ initial: false }); + +/** Options for narrow mode detection */ +export type NarrowOptions = { + /** + * Width threshold to start displaying the app in narrow mode + */ + threshold: number; + + /** + * A function called to override the detected value + */ + override?: (detected: boolean) => boolean; + + /** + * Set the initial value, if the platform doesn't support detecting + * viewport width. + */ + initial?: boolean; +}; + +/** + * Initialize narrow mode detection + * + * Note that this is not necessary in some simple use cases. For example, + * adjusting styles based on the viewport width can be done with CSS: + * ```css + * @media screen and (max-width: 800px) { + * /* styles for narrow mode * / + * } + * ``` + * + * Use this only if narrow mode needs to be detected programmatically. + */ +export const initNarrow = (options: NarrowOptions) => { + const threshold = options.threshold; + const override = options.override; + if (window && window.addEventListener && window.innerWidth !== undefined) { + const callback = + () => { + const newNarrow = window.innerWidth < threshold; + if (override) { + narrow.set(override(newNarrow)); + } else { + narrow.set(newNarrow); + } + } + window.addEventListener("resize", callback); + callback(); + } else if (options.initial !== undefined) { + narrow.set(options.initial); + } +}; + +/** Subscribe to narrow mode changes */ +export const addNarrowSubscriber = (subscriber: (narrow: boolean) => void, notifyImmediately?: boolean) => { + return narrow.subscribe(subscriber, notifyImmediately); +} + +/** Check if the app is in narrow mode */ +export const isNarrow = (): boolean => { + return narrow.get(); +} + +/** React hook to use narrow mode detection */ +export const useNarrow = () => { + return useSyncExternalStore(addNarrowSubscriber, isNarrow); +} diff --git a/packages/app/src/pure-contrib/platform.ts b/packages/app/src/pure-contrib/platform.ts new file mode 100644 index 0000000..30e8224 --- /dev/null +++ b/packages/app/src/pure-contrib/platform.ts @@ -0,0 +1,20 @@ +import { cell } from "@pistonite/pure/sync"; + +import { isMobile, isSmartTV, isWearable } from "mobile-device-detect"; + +const lessProductive = cell({ initial: isMobile || isSmartTV || isWearable }) + +export type PlatformOptions = { + /** Width threshold to start displaying the app in narrow mode */ + narrowModeThreadhold: number; +}; + + +export const initPlatform = async (options: PlatformOptions) => {} + +/** + * Detect if the platform is less productive than the conventional + * KVM setup - for example, mobile, tablet, wearable, etc. + */ +export const isLessProductive= (): boolean => { +} diff --git a/packages/app/src/runtime/.gitignore b/packages/app/src/runtime/.gitignore new file mode 100644 index 0000000..f9cee21 --- /dev/null +++ b/packages/app/src/runtime/.gitignore @@ -0,0 +1,3 @@ +# workex generated files +/interfaces/ +/sides/ diff --git a/packages/app/src/runtime/init.ts b/packages/app/src/runtime/init.ts new file mode 100644 index 0000000..cedc28b --- /dev/null +++ b/packages/app/src/runtime/init.ts @@ -0,0 +1,12 @@ +import { RuntimeApiClient } from "./interfaces/RuntimeApi.send.ts"; +import RuntimeWorker from "./worker.ts?worker"; + +/** + * Initialize the simulator runtime and make sure it's ready + */ +export async function initRuntime() { + const worker = new RuntimeWorker(); + const runtime = new RuntimeApiClient({worker}); + await runtime.handshake().established(); + return runtime; +} diff --git a/packages/app/src/runtime/protocol.ts b/packages/app/src/runtime/protocol.ts new file mode 100644 index 0000000..ff9f612 --- /dev/null +++ b/packages/app/src/runtime/protocol.ts @@ -0,0 +1,16 @@ +import { WorkexPromise } from "workex"; + +/** + * API provided by the simulator runtime + * + * @workex:send app + * @workex:recv runtime + */ +export interface RuntimeApi { + + /** + * Set the script for the runtime, which starts executing + * the script immediately + */ + setScript(script: string): WorkexPromise; +} diff --git a/packages/app/src/runtime/worker.ts b/packages/app/src/runtime/worker.ts new file mode 100644 index 0000000..908f58c --- /dev/null +++ b/packages/app/src/runtime/worker.ts @@ -0,0 +1,21 @@ +// import wasmUrl from "skybook-runtime-wasm/skybook_runtime_wasm_bg.wasm?url"; +import { parse_script } from "skybook-runtime-wasm"; + +import { Delegate, hostFromDelegate } from "workex"; + +import { bindRuntimeApiHost } from "./interfaces/RuntimeApi.recv"; +import { RuntimeApi } from "./protocol.ts"; + +async function boot() { + + const api = { + setScript: async (script) => { + return parse_script(script); + }, + } satisfies Delegate; + + const handshake = bindRuntimeApiHost(hostFromDelegate(api), { worker: self }); + await handshake.initiate(); +} + +void boot(); diff --git a/packages/app/src/theme/ThemeProvider.tsx b/packages/app/src/theme/ThemeProvider.tsx new file mode 100644 index 0000000..d798c77 --- /dev/null +++ b/packages/app/src/theme/ThemeProvider.tsx @@ -0,0 +1,23 @@ +import { FluentProvider, makeStyles, webDarkTheme, webLightTheme } from "@fluentui/react-components"; +import { useDark } from "@pistonite/pure-react"; +import type { PropsWithChildren } from "react"; + + +// const useStyles = makeStyles({ +// root: { +// width: "100%", +// height: "100%", +// } +// }); + +export const ThemeProvider: React.FC = ({ children }) => { + const dark = useDark(); + console.log("dark", dark); + // const styles = useStyles(); + const theme = dark ? webDarkTheme : webLightTheme; + return ( + + {children} + + ); +} diff --git a/packages/app/src/ui/ExtensionOpenButton.tsx b/packages/app/src/ui/ExtensionOpenButton.tsx new file mode 100644 index 0000000..bc31688 --- /dev/null +++ b/packages/app/src/ui/ExtensionOpenButton.tsx @@ -0,0 +1,93 @@ +import { Text, Button, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Tooltip, Field, Combobox, RadioGroup, Radio, Checkbox } from "@fluentui/react-components"; +import { WindowDevTools20Regular } from "@fluentui/react-icons"; +import { ExtensionOpenMode } from "application/extensionStore"; +import { useNarrow } from "pure-contrib/narrow"; +import { useState } from "react"; +import { useUITranslation } from "skybook-localization"; +import { isLessProductive } from "./platform"; + +export const ExtensionOpenButton: React.FC = () => { + const t = useUITranslation(); + + const narrow = useNarrow(); + + const [selectedId, setSelectedId] = useState(""); + const [selectedOpenMode, setSelectedOpenMode] = useState("secondary"); + const [isPersistChecked, setIsPersistChecked] = useState(true); + + let displayedOpenMode = selectedOpenMode; + const secondaryAvailable = !narrow && !isLessProductive; + if (!secondaryAvailable && selectedOpenMode === "secondary") { + displayedOpenMode = "primary"; + } + + + return ( + + + + + + + + + + + ); +}; diff --git a/packages/app/src/ui/ExtensionPanel.tsx b/packages/app/src/ui/ExtensionPanel.tsx new file mode 100644 index 0000000..531fef2 --- /dev/null +++ b/packages/app/src/ui/ExtensionPanel.tsx @@ -0,0 +1,92 @@ +import { memo } from "react"; +import { ExtensionTitlebar, ExtensionTitlebarMobile } from "./ExtensionTitlebar"; +import { isLessProductive } from "./platform"; +import { makeStyles } from "@fluentui/react-components"; +import { useCurrentPrimaryExtensionId, useCurrentSecondaryExtensionId, usePrimaryExtensionIds, useSecondaryExtensionIds } from "application/extensionStore"; +import { ExtensionWrapper } from "extensions/ExtensionWindow"; +import { useUIStore } from "./store"; +import { ResizeLayout } from "./components/ResizeLayout"; + +const useStyles = makeStyles({ + container: { + flex: 1, + display: "flex", + flexDirection: "column", + }, + main: { + flex: 1, + }, + extensionWindow: { + width: "100%", + height: "100%", + }, +}); + +const ExtensionPanelConnected: React.FC = () => { + const styles = useStyles(); + const primaryIds = usePrimaryExtensionIds(); + const secondaryIds = useSecondaryExtensionIds(); + const currentPrimaryId = useCurrentPrimaryExtensionId(); + const currentSecondaryId = useCurrentSecondaryExtensionId(); + + const primaryExtensionWindowPercentage = useUIStore(state => state.primaryExtensionWindowPercentage); + const setPrimaryExtensionWindowPercentage = useUIStore(state => state.setPrimaryExtensionWindowPercentage); + + const primaryWindow = ( + primaryIds.map((id, i) => ( +
+ +
+ )) + ); + const secondaryWindow = ( + secondaryIds.map((id, i) => ( +
+ +
+ )) + ); + const hasTwoWindows = currentPrimaryId && currentSecondaryId; + return ( +
+ { + isLessProductive ? + + : + + } +
+ { + !hasTwoWindows && primaryWindow + } + { + !hasTwoWindows && secondaryWindow + } + { + hasTwoWindows && ( + +
+ {primaryWindow} +
+
+ {secondaryWindow} +
+ +
+ ) + } +
+
+ ); +}; + +export const ExtensionPanel = memo(ExtensionPanelConnected); diff --git a/packages/app/src/ui/ExtensionTitlebar.tsx b/packages/app/src/ui/ExtensionTitlebar.tsx new file mode 100644 index 0000000..83c98a9 --- /dev/null +++ b/packages/app/src/ui/ExtensionTitlebar.tsx @@ -0,0 +1,134 @@ +import { Divider, makeStyles } from "@fluentui/react-components"; +import { useAllNonPopoutExtensionIds, useCurrentPrimaryExtensionId, useCurrentSecondaryExtensionId, useExtensionStore, usePrimaryExtensionIds, useSecondaryExtensionIds } from "application/extensionStore"; +import { ExtensionToolbar } from "./components/ExtensionToolbar"; +import { openExtensionPopup } from "application/extensionManager"; +import { ExtensionOpenButton } from "./ExtensionOpenButton"; +import { memo, useEffect, useState } from "react"; +import { isLessProductive } from "./platform"; + +const useStyles = makeStyles({ + bar: { + display: "flex", + flexDirection: "row", + gap: "4px", + }, + divider: { + maxWidth: "2px", + } +}); + +const ExtensionTitlebarConnected: React.FC = () => { + const styles = useStyles(); + + const currentPrimaryId = useCurrentPrimaryExtensionId(); + const currentSecondaryId = useCurrentSecondaryExtensionId(); + const primaryIds = usePrimaryExtensionIds(); + const secondaryIds = useSecondaryExtensionIds(); + const openExtension = useExtensionStore(state => state.open); + const closePrimary = useExtensionStore(state => state.closePrimary); + const closeSecondary = useExtensionStore(state => state.closeSecondary); + + const [barRef, setBarRef] = useState(null); + const [isNarrowLayout, setIsNarrowLayout] = useState(false); + + useEffect(() => { + if (!barRef) { + return; + } + const observer = new ResizeObserver(() => { + const {width} = barRef.getBoundingClientRect(); + setIsNarrowLayout(width<660); + }); + observer.observe(barRef); + return () => observer.disconnect(); + }, [barRef]); + + const primaryToolbar = + currentPrimaryId && ( + { + openExtensionPopup(currentPrimaryId); + closePrimary(); + }} + onSelect={(id) => { + openExtension(id, "primary"); + }} + /> + ); + + const secondaryToolbar = + currentSecondaryId && ( + { + openExtensionPopup(currentSecondaryId); + closeSecondary(); + }} + onSelect={(id) => { + openExtension(id, "secondary"); + }} + onClickClose={closeSecondary} + />); + + const twoLine = isNarrowLayout && currentPrimaryId && currentSecondaryId; + if (twoLine) { + return ( +
+
+ {primaryToolbar} + +
+ {secondaryToolbar} +
+ ); + } + + return ( +
+ {primaryToolbar} + { + currentPrimaryId && currentSecondaryId && ( + + ) + } + {secondaryToolbar} + { + currentPrimaryId && currentSecondaryId && ( + + ) + } + +
+ ); + +}; + +export const ExtensionTitlebar = memo(ExtensionTitlebarConnected); + +/** Titlebar for mobile platform with simplified controls */ +const ExtensionTitlebarMobileConnected: React.FC = () => { + const styles = useStyles(); + + const allIds = useAllNonPopoutExtensionIds(); + const currentId = useCurrentPrimaryExtensionId(); + const openExtension = useExtensionStore(state => state.open); + + + return ( +
+ { + openExtension(id, "primary"); + }} + fullWidth + /> +
+ ); +}; + +export const ExtensionTitlebarMobile = memo(ExtensionTitlebarMobileConnected); diff --git a/packages/app/src/ui/components/ExtensionToolbar.tsx b/packages/app/src/ui/components/ExtensionToolbar.tsx new file mode 100644 index 0000000..a7b4034 --- /dev/null +++ b/packages/app/src/ui/components/ExtensionToolbar.tsx @@ -0,0 +1,125 @@ +import { Button, Dropdown, Option, Tooltip, makeStyles, mergeClasses } from "@fluentui/react-components"; +import { Dismiss20Regular, WindowNew20Regular } from "@fluentui/react-icons"; + +import { useUITranslation } from "skybook-localization"; + +export type ExtensionToolbarProps = { + /** Id of the current opened extension */ + id: string; + + /** + * Id of all extensions selectable from this toolbar + * + * The options will be displayed using the `extension.${id}.name` translation + */ + allIds: string[]; + + /** + * Callback when the pop out button is pressed + * + * If not provided, the pop out button will be hidden + */ + onClickPopout?: () => void; + + /** + * Callback when the close button is pressed + * + * If not provided, the close button will be hidden + */ + onClickClose?: () => void; + + /** + * Callback when an extension is selected from the drop down + * + * Will not be invoked if the current extension is selected again + * from the drop down + */ + onSelect: (id: string) => void; + + /** + * If enabled, will add flex: 1 to the container and dropdown container + * so it's full width in the flex box parent + */ + fullWidth?: boolean; +}; + +const useStyles = makeStyles({ + container: { + display: "flex", + flexDirection: "row", + gap: "4px", + }, + fullWidth: { + flex: 1, + }, + selectorButton: { + // truncate text + overflowX: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + maxWidth: "200px", + } +}); + +export const ExtensionToolbar: React.FC = ({ + id, allIds, onClickPopout, onClickClose, onSelect, fullWidth +}) => { + const t = useUITranslation(); + const styles = useStyles(); + return ( +
+ + {t(`extension.${id}.name`)} + + } + selectedOptions={[id]} + onOptionSelect={(_, {optionValue}) => { + if (optionValue && optionValue !== id) { + onSelect(optionValue); + } + }} + > + { + allIds.map((id, i) => ( + + + + )) + } + + { onClickPopout && ( + +
+ + ); +}; diff --git a/packages/app/src/ui/components/ResizeLayout.tsx b/packages/app/src/ui/components/ResizeLayout.tsx new file mode 100644 index 0000000..0ad7a17 --- /dev/null +++ b/packages/app/src/ui/components/ResizeLayout.tsx @@ -0,0 +1,222 @@ +import { Divider, makeStyles, mergeClasses, tokens } from "@fluentui/react-components"; +import { Children, useRef, useState, type PropsWithChildren } from "react"; + + +export type ResizeLayoutProps = { + /** If the resize layout should be horizontal or vertical */ + vertical?: boolean; + + /** The minimum pixel width of the first child */ + minWidth?: number; + + /** The minimum pixel height of the first child */ + minHeight?: number; + + /** The current percentage size of the first child */ + valuePercent: number; + + /** Callback to set the percentage size of the first child */ + setValuePercent: (percent: number) => void; + + /** If the resizing is disabled */ + disabled?: boolean; + + /** Use the natural size instead of valuePercent */ + naturalSize?: boolean; + + /** Optimize for touch screen */ + touch?: boolean; +} & Omit, "ref" | "onMouseUp" | "onMouseLeave">; + +const useStyles = makeStyles({ + container: { + display: "flex", + }, + containerVertical: { + flexDirection: "column", + }, + containerHorizontal: { + flexDirection: "row", + }, + childContainer: { + // needed to anchor drag handle with position: absolute + position: "relative", + }, + secondChild: { + flex: 1, + }, + dragHandle: { + position: "absolute", + transition: "background-color 0.2s", + }, + dragHandleFirst: { + bottom: 0, + right: 0, + }, + dragHandleSecond: { + top: 0, + left: 0, + }, + dragHandleVertical: { + // for vertical resize, the handle itself is "horizontal" + width: "100%", + height: "3px", + cursor: "ns-resize", + }, + dragHandleHorizontal: { + // for horizontal resize, the handle itself is "vertical" + width: "3px", + height: "100%", + cursor: "ew-resize", + }, + dragHandleResizing: { + backgroundColor: "rgba(0, 0, 0, 0.1)", + zIndex: 10000, + }, + // dragHandleVisible: { + // transition: "background-color 0.2s", + // display: "flex", + // }, + dragHandleTouchVertical: { + height: "20px", + width: "100%", + }, + dragHandleTouchHorizontal: { + width: "20px", + height: "100%", + }, +}); + +/** + * A flex-box layout of 2 children, with a draggable divider between them. + */ +export const ResizeLayout: React.FC> = ({ + vertical, valuePercent, setValuePercent, disabled, naturalSize, minWidth, + minHeight, + touch, + children, ...props +}) => { + const [firstChild, secondChild] = Children.toArray(children); + + const styles = useStyles(); + const containerRef = useRef(null); + const firstRef = useRef(null); + // [startX, startY, startWidth, startHeight] + const [resizing, setResizing] = useState(undefined); + + const startResize = (e: React.MouseEvent | React.TouchEvent) => { + if (disabled || !firstRef.current) { + return; + } + const coords = getEventClientCoords(e); + if (!coords) { + return; + } + try { + e.preventDefault(); + e.stopPropagation(); + } catch { + // prevent default will fail for touch events + } + const first = firstRef.current.getBoundingClientRect(); + setResizing([coords.clientX, coords.clientY, first.width, first.height]) + }; + + const handleResize = (e: React.MouseEvent | React.TouchEvent) => { + if (disabled || !resizing || !containerRef.current || !firstRef.current) { + return; + } + const coords = getEventClientCoords(e); + if (!coords) { + return; + } + const { width: containerWidth, height: containerHeight } = containerRef.current.getBoundingClientRect(); + const [startX, startY, startWidth, startHeight] = resizing; + const deltaX = coords.clientX - startX; + const deltaY = coords.clientY - startY; + if (vertical) { + const newHeight = startHeight + deltaY; + setValuePercent((newHeight / containerHeight) * 100) + } else { + const newWidth = startWidth + deltaX; + setValuePercent((newWidth / containerWidth) * 100) + } + }; + return ( +
{ setResizing(undefined) }} + onMouseLeave={() => { setResizing(undefined) }} + onTouchEnd={() => { setResizing(undefined) }} + onMouseMove={handleResize} + onTouchMove={handleResize} + > +
+ {firstChild} + { + !disabled && ( +
+ ) + } +
+
+ { + !disabled && ( +
+ ) + } + {secondChild} +
+
+ ); +}; + +const getEventClientCoords = (e: React.TouchEvent | React.MouseEvent) => { + if ("touches" in e && e.touches[0]) { + const touch = e.touches[0]; + return { + clientX: touch.clientX, + clientY: touch.clientY + }; + } + if ("clientX" in e && "clientY" in e) { + return { + clientX: e.clientX, + clientY: e.clientY + }; + } + return undefined; +} diff --git a/packages/app/src/ui/platform.ts b/packages/app/src/ui/platform.ts new file mode 100644 index 0000000..e75a113 --- /dev/null +++ b/packages/app/src/ui/platform.ts @@ -0,0 +1,7 @@ + +import { isMobile, isSmartTV, isWearable } from "mobile-device-detect"; +/** + * Detect if the platform is less productive than the conventional + * KVM setup - for example, mobile, tablet, wearable, etc. + */ +export const isLessProductive= isMobile || isSmartTV || isWearable; diff --git a/packages/app/src/ui/store.ts b/packages/app/src/ui/store.ts new file mode 100644 index 0000000..96878f9 --- /dev/null +++ b/packages/app/src/ui/store.ts @@ -0,0 +1,24 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; + +export type UIStore = { + /** Percentage size of the extension panel */ + extensionPanelPercentage: number; + setExtensionPanelPercentage: (percentage: number) => void; + + /** Percentage size of the primary extension window */ + primaryExtensionWindowPercentage: number; + setPrimaryExtensionWindowPercentage: (percentage: number) => void; +}; + +export const useUIStore = create()(persist((set) => ({ + extensionPanelPercentage: 40, + setExtensionPanelPercentage: (percentage) => set({ extensionPanelPercentage: percentage }), + + primaryExtensionWindowPercentage: 50, + setPrimaryExtensionWindowPercentage: (percentage) => set({ primaryExtensionWindowPercentage: percentage }), + +}),{ + name: "Skybook.UI", + version: 1, + })); diff --git a/packages/app/tsconfig.app.json b/packages/app/tsconfig.app.json new file mode 100644 index 0000000..3ec77ac --- /dev/null +++ b/packages/app/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../config/tsconfig-vite-app.json", + "compilerOptions": { + "baseUrl": "src", + }, + "include": ["src"] +} diff --git a/app/tsconfig.json b/packages/app/tsconfig.json similarity index 100% rename from app/tsconfig.json rename to packages/app/tsconfig.json diff --git a/packages/app/tsconfig.node.json b/packages/app/tsconfig.node.json new file mode 100644 index 0000000..3dc1b02 --- /dev/null +++ b/packages/app/tsconfig.node.json @@ -0,0 +1,4 @@ +{ + "extends": "../../config/tsconfig-tool.json", + "include": ["vite.config.ts"] +} diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts new file mode 100644 index 0000000..ff63811 --- /dev/null +++ b/packages/app/vite.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import yaml from "@modyfi/vite-plugin-yaml"; +import wasm from "vite-plugin-wasm"; +import topLevelAwait from "vite-plugin-top-level-await"; +import tsConfigPaths from "vite-tsconfig-paths"; + +// import esbuildImportMetaUrlPlugin from "@codingame/esbuild-import-meta-url-plugin"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tsConfigPaths(), yaml(), wasm(), topLevelAwait()], + worker: { + plugins: () => [yaml(), tsConfigPaths(), + wasm(), topLevelAwait() + ], + format: "iife", + + }, + resolve: { + dedupe: ["@pistonite/pure"] + } + + + // optimizeDeps: { + // esbuildOptions: { + // plugins: [esbuildImportMetaUrlPlugin] + // } + // } +}) + diff --git a/packages/blueflame-macros/Cargo.toml b/packages/blueflame-macros/Cargo.toml new file mode 100644 index 0000000..3d86c76 --- /dev/null +++ b/packages/blueflame-macros/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "blueflame-macros" +version = "0.0.0" +edition = "2021" +description = "proc-macro crate for blueflame" + +[dependencies] + +[lib] +proc-macro = true diff --git a/packages/blueflame-macros/src/lib.rs b/packages/blueflame-macros/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/packages/blueflame/Cargo.toml b/packages/blueflame/Cargo.toml new file mode 100644 index 0000000..2de1b1c --- /dev/null +++ b/packages/blueflame/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "blueflame" +version = "0.0.0" +edition = "2021" + +[dependencies] +derive_more = { version = "1.0.0", features = ["constructor", "deref", "deref_mut"] } +enumset = "1.1.5" +rand_xoshiro = "0.6.0" +sha2 = "0.10.8" +thiserror = "2.0.9" + +[dependencies.uking-relocate-lib] +git = "https://github.com/Pistonight/symbotw" +rev = "57e51a922e4e3c83d13d97d6e183a32f0533113e" diff --git a/packages/blueflame/src/boot.rs b/packages/blueflame/src/boot.rs new file mode 100644 index 0000000..a584658 --- /dev/null +++ b/packages/blueflame/src/boot.rs @@ -0,0 +1,183 @@ +use std::sync::Arc; + +use uking_relocate_lib::singleton::{ObjType, Singleton, SingletonCreator}; +use uking_relocate_lib::{Env, Program}; + +use crate::error::Error as CrateError; +use crate::memory::{align_down, align_up, Memory, MemoryFlags, Proxies, Region, RegionType, SimpleHeap, PAGE_SIZE, REGION_ALIGN}; +use crate::processor::Processor; +use crate::Core; + +/// Error that only happens during boot +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + #[error("no PMDM singleton found in program image")] + NoPmdm, + #[error("PMDM address is impossible to satisfy: 0x{0:08x}")] + InvalidPmdmAddress(u64), + #[error("heap is too small: need at least {0} bytes")] + HeapTooSmall(u32), + #[error("region overlap: {0} and {1}")] + RegionOverlap(RegionType, RegionType), +} + + +/// Initialize memory for the process +/// +/// Return the memory state after all singletons are created and initialized +pub fn init_memory( + image: &Program, + stack_start: u64, + stack_size: u32, + pmdm_address: u64, + heap_size: u32, +) -> Result<(Memory, Proxies), CrateError> { + + // calculate heap start address + // we need the heap to be as small as possible, + // but the relative address of the singleton could be really big + // (e.g. a few GBs), so we need to adjust the heap start accordingly + // + // 0 heap_start s1 pmdm s2 + // |<--heap_adjustment-->| + // |<----pmdm_rel_address--->| + // |<----------pmdm.rel_start--------------------->| + // |<----------min_rel_start------->| + // |<---------------------------max_rel_start--------------------->| + // |<------------------------pmdm_address------------------>| + // || + // + // for any singleton: + // rel_start - heap_adjustment + heap_start = address + // + // heap_adjustment is positive and guarateed to be less than rel_start + // of any singleton + let pmdm = image.singleton_by_id(Singleton::PauseMenuDataMgr).ok_or(Error::NoPmdm)?; + if pmdm.rel_start as u64 > pmdm_address { + return Err(Error::InvalidPmdmAddress(pmdm_address).into()); + } + let min_heap_start = pmdm_address - pmdm.rel_start as u64; + let min_rel_start = image.singletons().iter().map(|s| s.rel_start).min().unwrap_or_default(); + let max_heap_start = min_heap_start + min_rel_start as u64; + let heap_start = align_down!(max_heap_start, REGION_ALIGN); + if heap_start < min_heap_start { + // somehow align down made it smaller + // maybe possible with some pmdm_address + return Err(Error::InvalidPmdmAddress(pmdm_address).into()); + } + let heap_adjustment = heap_start - min_heap_start; + + // calculate how much space will be needed for all the singletons + let max_rel_start = image.singletons().iter().map(|s| s.rel_start).max().unwrap_or_default(); + let heap_end = min_heap_start + max_rel_start as u64; + // align up to the next page, and reserve 1 page for some spacing + let heap_singletons_end = align_up!(heap_end, PAGE_SIZE as u64) + PAGE_SIZE as u64; + let heap_singletons_size = (heap_singletons_end - heap_start) as u32; + // make the first alloc look random + let page_off_alloc_start = 0x428; + let heap_min_size = heap_singletons_size + page_off_alloc_start; + let heap_size = align_up!(heap_size, PAGE_SIZE); + + if heap_size < heap_min_size { + return Err(Error::HeapTooSmall(heap_min_size).into()); + } + + // check the regions don't overlap before allocating memory + if overlaps(image.program_start, image.program_size, stack_start, stack_size) { + return Err(Error::RegionOverlap(RegionType::Program, RegionType::Stack).into()); + } + if overlaps(image.program_start, image.program_size, heap_start, heap_size) { + return Err(Error::RegionOverlap(RegionType::Program, RegionType::Heap).into()); + } + if overlaps(stack_start, stack_size, heap_start, heap_size) { + return Err(Error::RegionOverlap(RegionType::Stack, RegionType::Heap).into()); + } + + // construct the memory + + + let program_region = Arc::new(Region::new_program( + image.program_start, + image.program_size, + image.regions()).unwrap()); // TODO: error type + // + let stack_region = Arc::new(Region::new_rw(RegionType::Stack, stack_start, stack_size)); + let heap_region = Arc::new(SimpleHeap::new( + heap_start, heap_size, heap_min_size as u64 + heap_start)); + + let flags = MemoryFlags { + enable_strict_region: true, + enable_permission_check: true, + enable_allocated_check: true, + }; + + let mut memory = Memory::new(flags, program_region, stack_region, heap_region); + + // create a temporary processor to initialize the singletons + + let mut processor = Processor::default(); + let mut proxies = Proxies::default(); + + let mut singleton_init = SingletonInit { + env: image.env, + program_start: image.program_start, + core: processor.attach(&mut memory, &mut proxies), + heap_start_adjusted: heap_start - heap_adjustment, + }; + + for singleton in image.singletons() { + singleton.create_instance(&mut singleton_init)?; + } + + Ok((memory, proxies)) +} + +fn overlaps(a_start: u64, a_size: u32, b_start: u64, b_size: u32) -> bool { + let a_end = a_start + a_size as u64; + let b_end = b_start + b_size as u64; + (b_start < a_end && b_start >= a_start) || (b_end < a_end && b_end >= a_start) +} + +pub struct SingletonInit<'p, 'm, 'x> { + env: Env, + program_start: u64, + core: Core<'p, 'm, 'x>, + heap_start_adjusted: u64, +} + +impl SingletonCreator for SingletonInit<'_, '_, '_> { + type Error = CrateError; + + fn set_main_rel_pc(&mut self, pc: u32) -> Result<(), Self::Error> { + let main_offset = self.env.main_offset(); + // physical address of the instruction we need to set PC to + let address = self.program_start + main_offset as u64 + pc as u64; + + todo!() + } + + fn enter(&mut self, target: u32) -> Result<(), Self::Error> { + todo!() + } + + fn execute_until(&mut self, target: u32) -> Result<(), Self::Error> { + todo!() + } + + fn allocate(&mut self, rel_start: u32, size: u32) -> Result<(), Self::Error> { + let singleton_address = self.heap_start_adjusted + rel_start as u64; + todo!() // store the address in X0 + } + + fn execute_to_return(&mut self) -> Result<(), Self::Error> { + todo!() + } + + fn stop(&mut self) -> Result<(), Self::Error> { + todo!() + } + + fn make_proxy(&mut self, obj_type: ObjType, reg: u32) -> Result<(), Self::Error> { + todo!() + } +} diff --git a/packages/blueflame/src/error.rs b/packages/blueflame/src/error.rs new file mode 100644 index 0000000..8f8d71a --- /dev/null +++ b/packages/blueflame/src/error.rs @@ -0,0 +1,12 @@ +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + + #[error("boot crash: {0}")] + Boot(#[from] crate::boot::Error), + + #[error("execution error")] + Cpu, // TODO: CPU errors + + #[error("memory error: {0}")] + Mem(crate::memory::Error), +} diff --git a/packages/blueflame/src/lib.rs b/packages/blueflame/src/lib.rs new file mode 100644 index 0000000..53bede0 --- /dev/null +++ b/packages/blueflame/src/lib.rs @@ -0,0 +1,41 @@ +use memory::{Memory, Proxies}; +use processor::Processor; + +pub struct Core<'p, 'm, 'x> { + pub cpu: &'p mut Processor, + pub mem: &'m mut Memory, + pub proxies: &'x mut Proxies, +} + +/// Internal bindings to invoke functions +impl Core<'_, '_, '_> { + + // these functions are called internally by the call + // to execute commands + // + // these need to put the argument on the stack, set SP and PC + // correctly, and then run the function using the Processor + + + // 0x96efb8 + pub fn pmdm_item_get(&self, actor: &str, value: i32, modifier_info: u64) -> + Result<(), error::Error> { + todo!(); + } +} + +/// Memory implementation +pub mod memory; + + +pub mod error; + +mod loader; + +pub mod processor; + +/// Initialization for the memory +mod boot; + +/// Proxy objects +mod proxy; diff --git a/packages/blueflame/src/loader.rs b/packages/blueflame/src/loader.rs new file mode 100644 index 0000000..61d464d --- /dev/null +++ b/packages/blueflame/src/loader.rs @@ -0,0 +1,76 @@ +use std::collections::HashMap; + +use crate::Core; + + +// loader creates Memory and Processor instances +// it needs to do the following: (in this order) +// - create the executable memory pages and copy the executable in +// - relocate the executable, which means +// - put the real addresses of the symbols in the .got.plt +// - put the real addresses of functions in vtables +// +// - create and allocate the stack pages (4MB) +// - create the heap region +// - for each singleton: +// - allocate the memory in the heap region for its instance +// - where the memory is is defined by configuration, as we +// need to put those singletons in the same spot the real game would put it +// - simulate the createInstance function for the singleton, which +// - allocates memory (this is already done, just return the pointer from previous step) +// - call ctor of the Disposer - skip this for now and leave the disposer uninitialized, as we +// don't really care about it +// - call the ctor of the singleton - we DO care about this +// - write the singleton address to the sInstance field (in .data section) +// +// +// + +pub trait LoaderInfo { + + + /// Create a table of stub functions. + /// + /// If the PC of the processor matches a key, then the corresponding + /// function is called and returned + fn create_stub_function_table(&self) -> HashMap Result<(), ()>>>; + + /// physical address in .got.plt -> key for stub function table + fn get_external_symbol_table(&self) -> HashMap; + + /// Get the region information for the program, stack, and heap + fn get_regions(&self) -> Regions; + + fn get_executable(&self) -> Executable; + + /// Get the relative addresses of the singletons + /// to heap start + fn get_singletons(&self) -> Singletons; + + + +} + +pub struct Regions { + pub program: RegionInfo, + pub stack: RegionInfo, + pub heap: RegionInfo, +} + +pub struct RegionInfo { + pub start: u64, + pub size: usize, +} + +pub struct Executable { + data: Vec +} + +pub struct ExecutableSegment { + pub start: u32, + pub data: Vec +} + +pub struct Singletons { + pub pmdm: u64, +} diff --git a/packages/blueflame/src/memory/access.rs b/packages/blueflame/src/memory/access.rs new file mode 100644 index 0000000..b7ef89d --- /dev/null +++ b/packages/blueflame/src/memory/access.rs @@ -0,0 +1,69 @@ +use enumset::{enum_set, EnumSet, EnumSetType}; + + +/// Information for accessing memory for tracking and reporting +#[derive(Debug, Clone)] +pub struct MemAccess { + /// The type of access + pub typ: AccessType, + /// The physical address being accessed + pub addr: u64, + /// The number of bytes being accessed + pub bytes: u32, +} + +impl std::fmt::Display for MemAccess { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{:?} access to 0x{:x} for {} bytes", + self.typ, self.addr, self.bytes + ) + } +} + +#[derive(Debug, EnumSetType)] +pub enum AccessType { + /// Reading data from the memory + Read, + /// Writing data to the memory + Write, + /// Reading instruction from memory + Execute, +} + +impl AccessType { + /// Convert a permission bitmask to a permission set + /// The mask is: + /// - 0x4 for read + /// - 0x2 for write + /// - 0x1 for execute + pub const fn from_perms(perm: u32) -> EnumSet { + match perm { + 0x4 => enum_set!(AccessType::Read), + 0x2 => enum_set!(AccessType::Write), + 0x1 => enum_set!(AccessType::Execute), + 0x6 => enum_set!(AccessType::Read | AccessType::Write), + 0x5 => enum_set!(AccessType::Read | AccessType::Execute), + 0x3 => enum_set!(AccessType::Write | AccessType::Execute), + 0x7 => enum_set!(AccessType::Read | AccessType::Write | AccessType::Execute), + _ => EnumSet::empty(), + } + } + + pub fn to_perm(&self) -> u32 { + match self { + AccessType::Read => 0x4, + AccessType::Write => 0x2, + AccessType::Execute => 0x1, + } + } + + pub fn to_perms(set: &EnumSet) -> u32 { + let mut perms = 0; + for perm in set.iter() { + perms |= perm.to_perm(); + } + perms + } +} diff --git a/packages/blueflame/src/memory/error.rs b/packages/blueflame/src/memory/error.rs new file mode 100644 index 0000000..c908829 --- /dev/null +++ b/packages/blueflame/src/memory/error.rs @@ -0,0 +1,38 @@ +use enumset::EnumSet; + +use super::region::RegionType; +use super::access::MemAccess; + +/// Memory errors +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + #[error("permission denied: {0}")] + PermissionDenied(MemAccess), + #[error("page boundary hit: {0}")] + PageBoundary(MemAccess), + #[error("attempt to access invalid memory region: 0x{0:08x}")] + InvalidRegion(u64), + #[error("attempt to access address: 0x{0:08x}, which is not in {1:?}")] + DisallowedRegion(u64, EnumSet), + + /// Region must be valid, but it's not allocated + /// (suppressable with :disable mem-check-allocated + #[error("attempt to access unallocated memory: 0x{0:08x}")] + Unallocated(u64), + #[error("{1} region out of memory: 0x{0:08x}")] + OutOfMemory(u64, RegionType), + + #[error("proxy object is too small: {0} bytes, need at least 4 bytes")] + InvalidProxyObjectSize(u32), + #[error("proxy object 0x{1:08x} is corrupted: handle {0} is invalid")] + InvalidProxyHandle(u32, u64), + #[error("proxy object 0x{1:08x}#{0} is corrupted: written outside of proxy. size: {2}")] + CorruptedProxyObject(u32, u64, u32), + #[error("too many proxy objects")] + ProxyOutOfMemory, + + #[error("unexpected error: {0}")] + Unexpected(String), + + +} diff --git a/packages/blueflame/src/memory/heap.rs b/packages/blueflame/src/memory/heap.rs new file mode 100644 index 0000000..3de7d75 --- /dev/null +++ b/packages/blueflame/src/memory/heap.rs @@ -0,0 +1,64 @@ +use derive_more::derive::{Deref, DerefMut}; + +use super::{align_up, error::Error, region::{Region, RegionType}}; + + +/// A simple heap region implementation +/// +/// It makes sure that: +/// - The region start is page-aligned +/// - Singleton allocations are allocated so they have the same +/// offsets relative to each other regardless of the heap start +/// - All newer allocations come after the singletons +/// +/// Since the simulator doesn't make much heap allocation (usually), +/// freed memory are never reclaimed. This is fine, because +/// each re-run of the simulation will have a fresh heap. +/// +/// It doesn't track which regions are freed, so UAF won't be detected +/// and is completely safe in the simulation since there is essentially +/// no free. However, it does track which region are not yet +/// allocated and throw error +#[derive(Debug, Clone, Deref, DerefMut)] +pub struct SimpleHeap { + /// Internal storage of the heap + #[deref] + #[deref_mut] + region: Region, + + /// Address of the next allocation + next_alloc: u64, +} + +impl SimpleHeap { + /// Create a new heap region. `start_alloc` is where + /// the first allocation will be placed + pub fn new(heap_start: u64, heap_size: u32, start_alloc: u64) -> Self { + let region = Region::new_rw(RegionType::Heap, heap_start, heap_size); + Self { + region, + next_alloc: start_alloc, + } + } + + /// Allocate new space in the heap + /// + /// To keep things simple, the alignment is assumed to be 8 + pub fn alloc(&mut self, size: u32) -> Result { + let start = align_up!(self.next_alloc, 8); + if u64::MAX - start < size as u64 { + return Err(Error::OutOfMemory(start, RegionType::Heap)); + } + let end = start + size as u64; + if end >= self.region.start + self.region.capacity as u64 { + return Err(Error::OutOfMemory(end, RegionType::Heap)); + } + self.next_alloc = end; + Ok(start) + } + + /// Return if the address is in the allocated region of the heap + pub fn is_allocated(&self, addr: u64) -> bool { + return addr < self.next_alloc; + } +} diff --git a/packages/blueflame/src/memory/memory.rs b/packages/blueflame/src/memory/memory.rs new file mode 100644 index 0000000..2ead545 --- /dev/null +++ b/packages/blueflame/src/memory/memory.rs @@ -0,0 +1,169 @@ +use std::ops::DerefMut; +use std::sync::Arc; + +use derive_more::derive::Constructor; +use enumset::EnumSet; + +use super::error::Error; +use super::heap::SimpleHeap; +use super::page::Page; +use super::read::Reader; +use super::region::{Region, RegionType}; +use super::write::Writer; + +/// Memory of the simulated process +#[derive(Debug, Clone, Constructor)] +pub struct Memory { + /// Memory feature flags + pub flags: MemoryFlags, + /// program region + program: Arc, + /// stack region + stack: Arc, + /// heap region + pub heap: Arc, +} + +impl Memory { + /// Create a reader to start reading at address + /// + /// Only allow reading from certain regions if `region` is specified + pub fn read(&self, address: u64, region: Option>, execute: bool) -> Result { + let regions = if self.flags.enable_strict_region { + region.unwrap_or(EnumSet::all()) + } else { + EnumSet::all() + }; + if let Some((region, page, page_idx, off)) = self.get_region_by_addr(address) { + if !regions.contains(region.typ) { + return Err(Error::DisallowedRegion(address, regions)); + } + return Ok(Reader::new(self, region, page, page_idx, off, execute)); + } + // region read_by_addr will fail if the address is not allocated, + // in those cases, we want to return Unallocated error + if self.program.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + if self.stack.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + if self.heap.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + Err(Error::InvalidRegion(address)) + } + + /// Create a writer to start writing at address + /// + /// Only allow writing to certain regions if `region` is specified + pub fn write(&mut self, address: u64, region: Option>) -> Result { + let regions = if self.flags.enable_strict_region { + region.unwrap_or(EnumSet::all()) + } else { + EnumSet::all() + }; + if let Some((region, _, page_idx, off)) = self.get_region_by_addr(address) { + if !regions.contains(region.typ) { + return Err(Error::DisallowedRegion(address, regions)); + } + return Ok(Writer::new(self, region.typ, page_idx, off)); + } + // region read_by_addr will fail if the address is not allocated, + // in those cases, we want to return Unallocated error + if self.program.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + if self.stack.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + if self.heap.is_addr_in_region(address) { + return Err(Error::Unallocated(address)) + } + Err(Error::InvalidRegion(address)) + + } + + /// If `address` is inside a region, return the region, page, region page index, and page offset + /// + /// This does not check permissions or if the address + /// is in an unallocated part of the region + pub fn get_region_by_addr(&self, address: u64) -> Option<(&Region, &Page, u32, u32)> { + if let Some((page, idx, off)) = self.program.read_at_addr(address) { + return Some((self.program.as_ref(), page, idx, off)); + } + if let Some((page, idx, off)) = self.stack.read_at_addr(address) { + return Some((self.stack.as_ref(), page, idx, off)); + } + if let Some((page, idx, off)) = self.heap.read_at_addr(address) { + return Some((self.heap.as_ref(), page, idx, off)); + } + None + } + + // // remove this if not needed + // pub fn get_cloest_next_region_by_addr(&self, address: u64) -> Option<&Region> { + // if let Some((region, _, _, _)) = self.get_region_by_addr(address) { + // return Some(region); + // } + // let mut closest = None; + // let mut closest_dist = u64::MAX; + // if address < self.program.start { + // let dist = self.program.start - address; + // if dist < closest_dist { + // closest = Some(self.program.as_ref()); + // closest_dist = dist; + // } + // } + // if address < self.stack.start { + // let dist = self.stack.start - address; + // if dist < closest_dist { + // closest = Some(self.stack.as_ref()); + // closest_dist = dist; + // } + // } + // if address < self.heap.start { + // let dist = self.heap.start - address; + // if dist < closest_dist { + // closest = Some(self.heap.as_ref()); + // } + // } + // closest + // } + // + pub fn get_region(&self, typ: RegionType) -> &Region { + match typ { + RegionType::Program => self.program.as_ref(), + RegionType::Stack => self.stack.as_ref(), + RegionType::Heap => self.heap.as_ref(), + } + } + + /// Get region by type for mutation. The region's page table + /// will be cloned on write if it is shared + pub fn mut_region(&mut self, typ: RegionType) -> &mut Region { + match typ { + RegionType::Program => Arc::make_mut(&mut self.program), + RegionType::Stack => Arc::make_mut(&mut self.stack), + RegionType::Heap => Arc::make_mut(&mut self.heap).deref_mut() + } + } + + pub fn heap_mut(&mut self) -> &mut SimpleHeap { + Arc::make_mut(&mut self.heap) + } +} + +#[derive(Debug, Clone)] +pub struct MemoryFlags { + /// If enabled, region must be specified when accessing memory. + /// If the address is not in the specified regions, an error will be thrown + pub enable_strict_region: bool, + + /// If permission checks are enabled + pub enable_permission_check: bool, + + /// If an address is in the heap region, check + /// if it is in the allocated part of the region + pub enable_allocated_check: bool, +} diff --git a/packages/blueflame/src/memory/mod.rs b/packages/blueflame/src/memory/mod.rs new file mode 100644 index 0000000..573542e --- /dev/null +++ b/packages/blueflame/src/memory/mod.rs @@ -0,0 +1,58 @@ +mod page; +pub use page::*; +mod error; +pub use error::*; +mod heap; +pub use heap::*; +mod region; +pub use region::*; +mod access; +pub use access::*; +mod read; +pub use read::*; +mod write; +pub use write::*; +mod memory; +pub use memory::*; +mod proxy; +pub use proxy::*; + +macro_rules! align_down { + ($addr:expr, $align:expr) => { + $addr & !($align - 1) + }; +} +pub(crate) use align_down; + +macro_rules! align_up { + ($addr:expr, $align:expr) => {{ + let align = $align; + $crate::memory::align_down!($addr + align - 1, align) + }}; +} +pub(crate) use align_up; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_align_down() { + assert_eq!(align_down!(0x1000, 0x1000), 0x1000); + assert_eq!(align_down!(0x1001, 0x1000), 0x1000); + assert_eq!(align_down!(0x1456, 0x1000), 0x1000); + assert_eq!(align_down!(0x14567, 0x10000), 0x10000); + assert_eq!(align_down!(0x1fff, 0x1000), 0x1000); + assert_eq!(align_down!(0x2000, 0x1000), 0x2000); + } + + #[test] + fn test_align_up() { + assert_eq!(align_down!(0x1000, 0x1000), 0x1000); + assert_eq!(align_down!(0x1001, 0x1000), 0x2000); + assert_eq!(align_down!(0x1456, 0x1000), 0x2000); + assert_eq!(align_down!(0x14567, 0x10000), 0x20000); + assert_eq!(align_down!(0x1fff, 0x1000), 0x2000); + assert_eq!(align_down!(0x2000, 0x1000), 0x2000); + } +} diff --git a/packages/blueflame/src/memory/page.rs b/packages/blueflame/src/memory/page.rs new file mode 100644 index 0000000..7e1db68 --- /dev/null +++ b/packages/blueflame/src/memory/page.rs @@ -0,0 +1,101 @@ +use enumset::EnumSet; + +use super::access::AccessType; + +pub const PAGE_SIZE: u32 = 0x1000; + +/// A page in memory +#[derive(Debug, Clone)] +pub struct Page { + data: [u8; PAGE_SIZE as usize], + perm: EnumSet, +} + +impl Page { + /// Create a new page with the given permissions and zeroed data + pub fn zeroed(perm: EnumSet) -> Self { + Self { + data: [0; PAGE_SIZE as usize], + perm, + } + } + + pub fn from_slice(data: &[u8], perm: EnumSet) -> Self { + let mut page = Self::zeroed(perm); + page.data[..data.len()].copy_from_slice(data); + page + } + + /// Check if the page has all of the given permission set + pub fn has_permission(&self, perm: impl Into>) -> bool { + !self.perm.intersection(perm.into()).is_empty() + } + + /// Read a u8 at offset without checking permissions + #[inline] + pub fn read_u8(&self, off: u32) -> u8 { + self.data[off as usize] + } + + /// Write a u8 at offset without checking permissions + #[inline] + pub fn write_u8(&mut self, off: u32, val: u8) { + self.data[off as usize] = val; + } + + /// Read a u16 at offset without checking permissions or bounds + #[inline] + pub fn read_u16(&self, off: u32) -> u16 { + u16::from_le_bytes([self.data[off as usize], self.data[off as usize+ 1]]) + } + + /// Write a u16 at offset without checking permissions or bounds + #[inline] + pub fn write_u16(&mut self, off: u32, val: u16) { + for (i, b) in val.to_le_bytes().into_iter().enumerate() { + self.data[off as usize + i] = b; + } + } + + /// Read a u32 at offset without checking permissions or bounds + #[inline] + pub fn read_u32(&self, off: u32) -> u32 { + u32::from_le_bytes([ + self.data[off as usize], + self.data[off as usize + 1], + self.data[off as usize + 2], + self.data[off as usize + 3], + ]) + } + + /// Write a u32 at offset without checking permissions or bounds + #[inline] + pub fn write_u32(&mut self, off: u32, val: u32) { + for (i, b) in val.to_le_bytes().into_iter().enumerate() { + self.data[off as usize + i] = b; + } + } + + /// Read a u64 at offset without checking permissions or bounds + #[inline] + pub fn read_u64(&self, off: u32) -> u64 { + u64::from_le_bytes([ + self.data[off as usize], + self.data[off as usize + 1], + self.data[off as usize + 2], + self.data[off as usize + 3], + self.data[off as usize + 4], + self.data[off as usize + 5], + self.data[off as usize + 6], + self.data[off as usize + 7], + ]) + } + + /// Write a u64 at offset without checking permissions or bounds + #[inline] + pub fn write_u64(&mut self, off: u32, val: u64) { + for (i, b) in val.to_le_bytes().into_iter().enumerate() { + self.data[off as usize + i] = b; + } + } +} diff --git a/packages/blueflame/src/memory/proxy.rs b/packages/blueflame/src/memory/proxy.rs new file mode 100644 index 0000000..bed4b86 --- /dev/null +++ b/packages/blueflame/src/memory/proxy.rs @@ -0,0 +1,198 @@ +use std::sync::Arc; + +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro256PlusPlus; +use sha2::{Digest, Sha256}; + +use super::error::Error; +use super::memory::Memory; +use super::region::RegionType; + +/// The maximum number of proxy objects per type +pub const MAX_OBJECTS: u32 = 1024000; + +/// Holds all proxy objects in memory +#[derive(Default, Clone)] +pub struct Proxies { + // just as a placeholder + string_proxies: Arc>, +} + +impl Proxies { + /// (EXAMPLE) operate on a string proxy at the given address + pub fn get_string(&self, mem: &Memory, address: u64) -> Result<&String, Error> { + self.string_proxies.get_at_addr(mem, address) + } + + /// (EXAMPLE) operate on a string proxy at the given address for mutation + pub fn mut_string<'s>(&'s mut self, mem: &mut Memory, address: u64) -> Result<&'s mut String, Error> { + Arc::make_mut(&mut self.string_proxies).mut_at_addr(mem, address) + } + + /// (EXAMPLE) allocate a string proxy in memory and returns a pointer to it + pub fn allocate_string(&mut self, mem: &mut Memory, s: String) -> Result { + Arc::make_mut(&mut self.string_proxies).allocate(mem, s) + } + +} + +impl ProxyObject for String { + fn mem_size(&self) -> u32 { + 0x100 + } +} + +#[derive(Clone)] +pub struct ProxyList { + rng: Xoshiro256PlusPlus, + objects: Vec>>, +} + +impl Default for ProxyList { + fn default() -> Self { + Self { + // same seed for every run + rng: Xoshiro256PlusPlus::seed_from_u64(0), + objects: Vec::new(), + } + } +} + +#[derive(Clone)] +struct Entry { + /// The proxy object (clone on write) + obj: T, + /// The hash of the object data in memory, initialized as random + integrity: [u8; 32], +} + +impl ProxyList { + /// Allocate a new proxy object in memory and return its address + pub fn allocate(&mut self, mem: &mut Memory, t: T) -> Result { + // allocate the proxy object in memory + let pointer = mem.heap_mut().alloc(t.mem_size())?; + self.create_entry(mem, pointer, t)?; + Ok(pointer) + } + + /// Create a new proxy object at the given pointer. + /// + /// Return the handle to the proxy object + /// + /// # Error + /// If error occurs, a potentially corrupted object will be left in memory, + /// and the entry is not created + fn create_entry(&mut self, mem: &mut Memory, pointer: u64, t: T) -> Result { + // allocate new entry and handle + if self.objects.len() >= MAX_OBJECTS as usize { + return Err(Error::ProxyOutOfMemory); + } + let mut integrity = [0; 32]; + let handle = self.objects.len() as u32; + Self::write_proxy_object(&mut self.rng, mem, pointer, handle, &t, &mut integrity)?; + // creating entry here to help elide copying + self.objects.push(Arc::new(Entry { + obj: t, + integrity + })); + Ok(handle) + } + + /// Write a proxy object to memory + fn write_proxy_object(rng: &mut Xoshiro256PlusPlus, mem: &mut Memory, pointer: u64, handle: u32, t: &T, hash_out: &mut [u8; 32]) -> Result<(), Error> { + let size = t.mem_size(); + if size < 4 { + return Err(Error::InvalidProxyObjectSize(size)); + } + let mut hash = Sha256::new(); + let mut w = mem.write(pointer, Some(RegionType::Heap.into()))?; + w.write_u32(handle)?; + hash.update(handle.to_le_bytes()); + + // create garbage data + let garbage_size = size - 4; + let chunks = garbage_size / 8; + for _ in 0..chunks { + let n = rng.next_u64(); + w.write_u64(n)?; + hash.update(&n.to_le_bytes()); + } + let remaining = garbage_size % 8; + if remaining > 0 { + let n = rng.next_u64(); + let bytes = n.to_le_bytes(); + for i in 0..remaining { + w.write_u8(bytes[i as usize])?; + } + hash.update(&bytes[..remaining as usize]); + } + *hash_out = hash.finalize().into(); + Ok(()) + } + + /// Get the object at the given address in memory as a proxy object + pub fn get_at_addr(&self, mem: &Memory, address: u64) -> Result<&T, Error> { + let handle = self.get_checked_handle(mem, address)?; + let e = &self.objects[handle as usize]; + Ok(&e.obj) + } + + /// Get the object at the given address in memory as a proxy object + /// for mutation. + /// + /// The proxy object is currently shared, it will be cloned, + /// and the proxy will receive a new integrity hash. However, + /// no cloning or updating will occur if the object is not shared. + pub fn mut_at_addr<'s>(&'s mut self, mem: &mut Memory, pointer: u64) -> Result<&'s mut T, Error> { + let handle = self.get_checked_handle(mem, pointer)?; + // get mut object, clone on write + // use pointer equality to check if it's cloned + // note we cannot make multiple make_mut or get_mut calls, + // because it's possible the object is changed in between + let ptr_old = Arc::as_ptr(&self.objects[handle as usize]) as usize; + let entry = Arc::make_mut(&mut self.objects[handle as usize]); + let copied = (std::ptr::from_ref(entry) as usize) != ptr_old; + + // update the object in memory to a fresh copy + if copied { + Self::write_proxy_object(&mut self.rng, mem, pointer, handle, &entry.obj, &mut entry.integrity)?; + } + Ok(&mut entry.obj) + } + + /// Read the object at the given address and check its integrity. + /// If OK, return the handle + /// + /// The entry is not returned to avoid borrowing + fn get_checked_handle(&self, mem: &Memory, pointer: u64) -> Result { + let mut hash = Sha256::new(); + // read the handle + let mut r = mem.read(pointer, Some(RegionType::Heap.into()), false)?; + let handle: u32 = r.read_u32()?; + hash.update(handle.to_le_bytes()); + let entry = match self.objects.get(handle as usize) { + Some(obj) => obj, + None => return Err(Error::InvalidProxyHandle(handle, pointer)), + }; + let size = entry.obj.mem_size(); + let mut data = Vec::with_capacity(size as usize); + for _ in 4..size { + data.push(r.read_u8()?); + } + hash.update(&data); + let integrity: [u8; 32] = hash.finalize().into(); + if integrity != entry.integrity { + return Err(Error::CorruptedProxyObject(handle, pointer, size)); + } + + Ok(handle) + } + + +} + +pub trait ProxyObject: Clone + Send + Sync { + /// Get the size of the object to mock in memory + /// The size must be at least 4 bytes + fn mem_size(&self) -> u32; +} diff --git a/packages/blueflame/src/memory/read.rs b/packages/blueflame/src/memory/read.rs new file mode 100644 index 0000000..bbc0c16 --- /dev/null +++ b/packages/blueflame/src/memory/read.rs @@ -0,0 +1,194 @@ +use super::access::{AccessType, MemAccess}; +use super::error::Error; +use super::page::{Page, PAGE_SIZE}; +use super::region::{Region, RegionType}; +use super::Memory; + +/// Stream reader from memory +pub struct Reader<'m> { + /// Memory being read + memory: &'m Memory, + /// The current region being read + region: &'m Region, + /// The current page being read + page: &'m Page, + /// Index of the page in the current region + region_page_idx: u32, + /// Current offset into the current page + page_off: u32, + /// If the read is for execution, so the execute permission is checked + execute: bool, +} + +impl<'m> Reader<'m> { + pub fn new(memory: &'m Memory, region: &'m Region, page: &'m Page, region_page_idx: u32, page_off: u32, execute: bool) -> Self { + Self { + memory, + region, + page, + region_page_idx, + page_off, + execute, + } + } + + /// Skip `len` bytes in the memory + #[inline] + pub fn skip(&mut self, len: u32) { + self.page_off += len; + // checks are done in prep_read, the next time a read is performed + // this is so that if we read the last data and advance into + // invalid memory, no exception will be thrown + } + + /// Get the current reading physical address + pub fn current_addr(&self) -> u64 { + self.region.start + (self.region_page_idx as u64 * PAGE_SIZE as u64) + self.page_off as u64 + } + + /// Read a `u8` from the memory, advance by 1 byte + #[inline] + pub fn read_u8>(&mut self) -> Result { + self.prep_read(1)?; + let val = self.page.read_u8(self.page_off); + self.skip(1); + + Ok(val.into()) + } + + /// Read a `i8` from the memory, advance by 1 byte + pub fn read_i8>(&mut self) -> Result { + let val: u8 = self.read_u8()?; + Ok((val as i8).into()) + } + + /// Read a `u16` from the memory, advance by 2 bytes + #[inline] + pub fn read_u16>(&mut self) -> Result { + self.prep_read(2)?; + let val = self.page.read_u16(self.page_off); + self.skip(2); + + Ok(val.into()) + } + + /// Read a `i16` from the memory, advance by 2 bytes + pub fn read_i16>(&mut self) -> Result { + let val: u16 = self.read_u16()?; + Ok((val as i16).into()) + } + + /// Read a `u32` from the memory, advance by 4 bytes + #[inline] + pub fn read_u32>(&mut self) -> Result { + self.prep_read(4)?; + let val = self.page.read_u32(self.page_off); + self.skip(4); + + Ok(val.into()) + } + + /// Read a `i32` from the memory, advance by 4 bytes + pub fn read_i32>(&mut self) -> Result { + let val: u32 = self.read_u32()?; + Ok((val as i32).into()) + } + + /// Read a `u64` from the memory, advance by 8 bytes + #[inline] + pub fn read_u64>(&mut self) -> Result { + self.prep_read(8)?; + let val = self.page.read_u64(self.page_off); + self.skip(8); + + Ok(val.into()) + } + + /// Read a `i64` from the memory, advance by 8 bytes + pub fn read_i64>(&mut self) -> Result { + let val: u64 = self.read_u64()?; + Ok((val as i64).into()) + } + + /// Read a `f32` from the memory, advance by 4 bytes + pub fn read_f32>(&mut self) -> Result { + let val: u32 = self.read_u32()?; + Ok(f32::from_bits(val).into()) + } + + /// Read a `f64` from the memory, advance by 8 bytes + pub fn read_f64>(&mut self) -> Result { + let val: u64 = self.read_u64()?; + Ok(f64::from_bits(val).into()) + } + + /// Prepare a read + /// + /// First it will make sure the region and page reference are valid, + /// then, it will check if the read is allowed + fn prep_read(&mut self, len: u32) -> Result<(), Error> { + // first check if we are still inside the region + let current_addr = self.current_addr(); + if current_addr >= self.region.get_end() { + // advance to next region if possible + match self.memory.get_region_by_addr(current_addr) { + None => { + return Err(Error::InvalidRegion(current_addr)); + } + Some((region, page, idx, off)) => { + // fix up the state + self.region = region; + self.page = page; + self.region_page_idx = idx; + self.page_off = off; + } + } + } + // advance to the next page in the region if needed + if self.page_off >= PAGE_SIZE { + self.region_page_idx += self.page_off / PAGE_SIZE; + self.page_off = self.page_off % PAGE_SIZE; + self.page = match self.region.get(self.region_page_idx) { + Some(page) => page.as_ref(), + None => return Err(Error::Unallocated(current_addr)), + } + } + + // now check we can actually read `len` bytes at the current address + if self.memory.flags.enable_allocated_check && self.region.typ == RegionType::Heap { + if !self.memory.heap.is_allocated(current_addr) { + return Err(Error::Unallocated(current_addr)); + } + } + + if self.memory.flags.enable_permission_check { + if self.execute { + if !self.page.has_permission(AccessType::Read | AccessType::Execute) { + return Err(Error::PermissionDenied(MemAccess { + typ: AccessType::Execute, + addr: self.current_addr(), + bytes: len, + })); + } + }else { + if !self.page.has_permission(AccessType::Read) { + return Err(Error::PermissionDenied(MemAccess { + typ: AccessType::Read, + addr: self.current_addr(), + bytes: len, + })); + } + } + } + + if self.page_off + len > PAGE_SIZE { + return Err(Error::PageBoundary(MemAccess { + typ: AccessType::Read, + addr: self.current_addr(), + bytes: len, + })); + } + + Ok(()) + } +} diff --git a/packages/blueflame/src/memory/region.rs b/packages/blueflame/src/memory/region.rs new file mode 100644 index 0000000..e62d5de --- /dev/null +++ b/packages/blueflame/src/memory/region.rs @@ -0,0 +1,206 @@ +use std::{sync::Arc}; + +use enumset::{EnumSet, EnumSetType}; +use uking_relocate_lib::ProgramRegion; + + +use super::access::AccessType; +use super::error::Error; +use super::page::{Page, PAGE_SIZE}; +use super::{align_down, align_up}; + + +pub const REGION_ALIGN: u64 = 0x10000; + + +/// Memory region implementation +/// +/// A region is a contiguous block of physical memory with +/// a starting address aligned to 0x10000 and a fixed size. +/// +/// Cloning a region will clone the page table, +/// but the page contents are clone-on-write +#[derive(Debug, Clone)] +pub struct Region { + pub typ: RegionType, + /// Physical start address of the region. Must be aligned to 0x10000 + pub start: u64, + /// Maximum capacity of the region in bytes + pub capacity: u32, + + pages: Vec>, +} + +impl Region { + /// Construct a program region from program region definition + /// + /// All pages in the program region are eagerly allocated. For simplicity, + /// this also include blank pages excluded from the image, which are zeroed. + /// The entire program region is around 70MB, which should be well under + /// the memory limit for WASM32 + /// + /// The program region is assumed to be page-aligned, but as fail-safe, + /// it will be aligned up to the next page boundary + /// + /// `program_start` is the physical address where the program is loaded + /// will be aligned down to the nearest 0x10000, if not already + pub fn new_program(program_start: u64, program_size: u32, regions: &[ProgramRegion]) -> Result< Self, Error> { + let start = align_down!(program_start, REGION_ALIGN); + let num_pages = align_up!(program_size, PAGE_SIZE) / PAGE_SIZE; + let mut pages = Vec::with_capacity(num_pages as usize); + // construct all the pages + let mut current_start: u32 = 0; + for region in regions { + // align down just for safety, if the program image is not aligned, + // it's bad anyway + let region_start = align_down!(region.rel_start, PAGE_SIZE); + if current_start > region_start { + // should not happen unless the program image is bad + return Err(Error::Unexpected(format!("program image has overlapping regions! current: 0x{:08x} > next: 0x{:08x}", current_start, region_start))); + } + while current_start < region_start { + // invalid regions are supposed to be inaccessible, + // so we don't give any permission + let page = Arc::new(Page::zeroed(EnumSet::empty())); + pages.push(page); + current_start += PAGE_SIZE; + } + // number of pages for this region in the image, align just for safety + let data_len = region.data().len() as u32; + let permissions = AccessType::from_perms(region.permissions); + let num_pages_curr = align_up!(data_len, PAGE_SIZE) / PAGE_SIZE; + for i in 0..num_pages_curr { + // usize should be either 32 or 64 on our supported platforms + let s = (i * PAGE_SIZE) as usize; + let e = ((i + 1) * PAGE_SIZE).min(data_len) as usize; + let page = Arc::new(Page::from_slice(region.data()[s..e].as_ref(), permissions)); + pages.push(page); + current_start += PAGE_SIZE; + } + } + + while current_start < program_size { + let page = Arc::new(Page::zeroed(EnumSet::empty())); + pages.push(page); + current_start += PAGE_SIZE; + } + Ok(Self { + typ: RegionType::Program, + start, + capacity: program_size, + pages, + }) + } + + /// Construct a dynamic RW region + /// + /// The dynamic regions are used for stack and heap. In the simulator, + /// they are all pretty small, so we also pre-allocate all the pages + /// for simplicity + pub fn new_rw(region_type: RegionType, start: u64, size: u32) -> Self { + let start = align_down!(start, REGION_ALIGN); + let num_pages = align_up!(size, PAGE_SIZE) / PAGE_SIZE; + let mut pages = Vec::with_capacity(num_pages as usize); + for _ in 0..num_pages { + let page = Arc::new(Page::zeroed(AccessType::Read | AccessType::Write)); + pages.push(page); + } + Self { + typ: region_type, + start, + capacity: size, + pages, + } + } + + /// Get the allocated size of the region in bytes + /// + /// In the current implementation, this is always equal to the capacity + pub fn len_bytes(&self) -> u32 { + self.pages.len() as u32 * PAGE_SIZE + } + + /// Get the end physical address of the region (exclusive) + pub fn get_end(&self) -> u64 { + self.start + self.capacity as u64 + } + + /// Get page by page index, returns None if the page is not allocated + pub fn get(&self, page_idx: u32) -> Option<&Arc> { + self.pages.get(page_idx as usize) + } + + /// Get mutable page reference by page index, returns None if the page is not allocated + /// + /// If the page is currently shared, it will be cloned (clone-on-write) + pub fn get_mut(&mut self, page_idx: u32) -> Option<&mut Page> { + self.pages.get_mut(page_idx as usize).map(|page| Arc::make_mut(page)) + } + + /// Return true if the address is in addresses reserved for this region + pub fn is_addr_in_region(&self, addr: u64) -> bool { + addr >= self.start && addr < self.start + self.capacity as u64 + } + + + /// Get the page for the given address as (Page, page_index, page_offset) + /// + /// Returns `None` if the address is not in this region, + /// or if the page is unallocated. + pub fn read_at_addr(&self, addr: u64) -> Option<(&Page, u32, u32)> { + if addr < self.start || addr >= self.start + self.len_bytes() as u64{ + return None; + } + // relative address in the region + let rel_addr = addr - self.start; + let region_page_idx = (rel_addr / PAGE_SIZE as u64) as u32; + let page = self.pages.get(region_page_idx as usize)?; + let page_off = (rel_addr % PAGE_SIZE as u64) as u32; + Some((page.as_ref(), region_page_idx, page_off)) + } + + // /// Split the address into region page index and offset + // /// + // /// Returns (0, 0) if the address is not in this region - + // /// only use if you have already checked that the address is in this region + // pub fn split_addr(&self, addr: u64) -> (usize, usize) { + // if addr < self.start || addr >= self.start + self.len_bytes() { + // return (0, 0); + // } + // let region_addr = addr - self.start; + // let region_page_idx = region_addr / PAGE_SIZE as u64; + // let page_off = (region_addr % PAGE_SIZE as u64) as usize; + // (region_page_idx as usize, page_off) + // } +} + + +/// Type of the region used for tracking and debugging purposes +/// +/// Unlike a regular OS where the regions are ordered program -> heap -> stack +/// from low to high virtual addresses. NX does not have such system +/// and these regions are physical memory that can be in any order. +#[derive(Debug, EnumSetType)] +pub enum RegionType { + /// The program segments + Program, + /// The stack segment + /// + /// Usually this contains stacks for all threads, + /// but the simulator will only have one thread + Stack, + /// The heap segment + Heap + + // do we need TLS (Thread Local)? +} + +impl std::fmt::Display for RegionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RegionType::Program => write!(f, "program"), + RegionType::Stack => write!(f, "stack"), + RegionType::Heap => write!(f, "heap"), + } + } +} diff --git a/packages/blueflame/src/memory/write.rs b/packages/blueflame/src/memory/write.rs new file mode 100644 index 0000000..f18db10 --- /dev/null +++ b/packages/blueflame/src/memory/write.rs @@ -0,0 +1,182 @@ +use super::{access::{AccessType, MemAccess}, error::Error, page::{Page, PAGE_SIZE}, region::{Region, RegionType}, Memory}; + +/// Stream writer to memory +pub struct Writer<'m> { + /// Memory being written to + /// + /// Since only one mutable reference can exist in Rust, + /// we have to get the mutable page reference + /// for every write operation + memory: &'m mut Memory, + /// Current region being written to + region_type: RegionType, + /// Index of the page currently being written to + region_page_idx: u32, + /// Offset into the current page + page_off: u32, +} + +impl<'m> Writer<'m> { + pub fn new(memory: &'m mut Memory, region_type: RegionType, region_page_idx: u32, page_off: u32) -> Self { + Self { + memory, + region_type, + region_page_idx, + page_off, + } + } + /// Skip `len` bytes in the memory + pub fn skip(&mut self, len: u32) { + self.page_off += len; + } + + fn region(&self) -> &Region { + self.memory.get_region(self.region_type) + } + + fn region_mut(&mut self) -> &mut Region { + self.memory.mut_region(self.region_type) + } + + /// Get the current reading address + pub fn current_addr(&self) -> u64 { + self.region().start + (self.region_page_idx as u64 * PAGE_SIZE as u64) + self.page_off as u64 + } + + /// Write a `u8` to the memory, advance by 1 byte + #[inline] + pub fn write_u8(&mut self, val: impl Into) -> Result<(), Error> { + self.checked_page_mut(1, |page, off| { + page.write_u8(off, val.into()) + }) + } + + /// Read a `i8` from the memory, advance by 1 byte + pub fn write_i8(&mut self, val: impl Into) -> Result<(), Error> { + self.write_u8(val.into() as u8) + } + + /// Write a `u16` to the memory, advance by 2 bytes + #[inline] + pub fn write_u16(&mut self, val: impl Into) -> Result<(), Error> { + self.checked_page_mut(2, |page, off| { + page.write_u16(off, val.into()) + }) + } + + /// Write a `i16` to the memory, advance by 2 bytes + pub fn write_i16(&mut self, val: impl Into) -> Result<(), Error> { + self.write_u16(val.into() as u16) + } + + /// Write a `u32` to the memory, advance by 4 bytes + #[inline] + pub fn write_u32(&mut self, val: impl Into) -> Result<(), Error> { + self.checked_page_mut(4, |page, off| { + page.write_u32(off, val.into()) + }) + } + + /// Write a `i32` to the memory, advance by 4 bytes + pub fn write_i32(&mut self, val: impl Into) -> Result<(), Error> { + self.write_u32(val.into() as u32) + } + + /// Write a `u64` to the memory, advance by 8 bytes + #[inline] + pub fn write_u64(&mut self, val: impl Into) -> Result<(), Error> { + self.checked_page_mut(8, |page, off| { + page.write_u64(off, val.into()) + }) + } + + /// Write a `i64` to the memory, advance by 8 bytes + pub fn write_i64(&mut self, val: impl Into) -> Result<(), Error> { + self.write_u64(val.into() as u64) + } + + /// Write a `f32` to the memory, advance by 4 bytes + pub fn write_f32(&mut self, val: impl Into) -> Result<(), Error> { + let val: u32 = val.into().to_bits(); + self.write_u32(val) + } + + /// Write a `f64` to the memory, advance by 8 bytes + pub fn write_f64(&mut self, val: impl Into) -> Result<(), Error> { + let val: u64 = val.into().to_bits(); + self.write_u64(val) + } + + /// Prepare a write, then operate on the page + /// + /// This must be done through a FnOnce closure because of borrowing rules + fn checked_page_mut( + &mut self, len: u32, f:F) -> Result<(), Error> { + { + // first check if we are still inside the region + let region = self.region(); + let current_addr = region.start + (self.region_page_idx as u64 * PAGE_SIZE as u64) + self.page_off as u64; + if current_addr >= region.get_end() { + // advance to next region if possible + match self.memory.get_region_by_addr(current_addr) { + None => { + return Err(Error::InvalidRegion(current_addr)); + } + Some((region, _, idx, off)) => { + // fix up the state + self.region_type = region.typ; + self.region_page_idx = idx; + self.page_off = off; + } + } + } + } + // advance to the next page in the region if needed + if self.page_off >= PAGE_SIZE { + self.region_page_idx += self.page_off / PAGE_SIZE; + self.page_off = self.page_off % PAGE_SIZE; + if self.region().get(self.region_page_idx).is_none() { + return Err(Error::Unallocated(self.current_addr())); + } + } + + // now check we can actually read `len` bytes at the current address + if self.memory.flags.enable_allocated_check && self.region().typ == RegionType::Heap { + let current_addr = self.current_addr(); + if !self.memory.heap.is_allocated(current_addr) { + return Err(Error::Unallocated(current_addr)); + } + } + // copy these value out since we will lose immutable borrow to self + let region_page_idx = self.region_page_idx; + let check_permission = self.memory.flags.enable_permission_check; + let page_off = self.page_off; + // re-borrow the region as mutable and clone on write + let region = self.region_mut(); + let page = match region.get_mut(region_page_idx) { + Some(page) => page, + None => return Err(Error::Unallocated(self.current_addr())), + }; + + if check_permission && !page.has_permission(AccessType::Write) { + return Err(Error::PermissionDenied(MemAccess { + typ: AccessType::Write, + addr: self.current_addr(), + bytes: len, + })); + } + + if page_off + len > PAGE_SIZE { + return Err(Error::PageBoundary(MemAccess { + typ: AccessType::Write, + addr: self.current_addr(), + bytes: len, + })); + } + + f(page, page_off); + + self.page_off += len; + Ok(()) + } +} diff --git a/packages/blueflame/src/processor/mod.rs b/packages/blueflame/src/processor/mod.rs new file mode 100644 index 0000000..fbe241b --- /dev/null +++ b/packages/blueflame/src/processor/mod.rs @@ -0,0 +1,26 @@ + +use std::collections::HashMap; + +use crate::{memory::{Memory, Proxies}, Core}; + +pub struct Processor { + // TODO: registers + pub stub_functions: HashMap Result<(), ()>>>, +} + +impl Default for Processor { + fn default() -> Self { + todo!() + } +} + +impl Processor { + /// Attach the processor to a memory instance + pub fn attach<'p, 'm, 'x>(&'p mut self, mem: &'m mut Memory, proxies: &'x mut Proxies) -> Core<'p, 'm, 'x> { + Core { + cpu: self, + mem, + proxies, + } + } +} diff --git a/packages/blueflame/src/proxy/mod.rs b/packages/blueflame/src/proxy/mod.rs new file mode 100644 index 0000000..348344e --- /dev/null +++ b/packages/blueflame/src/proxy/mod.rs @@ -0,0 +1,4 @@ + +/// TODO: TriggerParam +pub struct GdtTriggerParam { +} diff --git a/packages/extension-api/Taskfile.yml b/packages/extension-api/Taskfile.yml new file mode 100644 index 0000000..6778374 --- /dev/null +++ b/packages/extension-api/Taskfile.yml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + build: + cmds: + - workex -p skyb-0.0.1 src/protocol.ts --lib-path workex --no-lib diff --git a/packages/extension-api/package.json b/packages/extension-api/package.json new file mode 100644 index 0000000..2fb9653 --- /dev/null +++ b/packages/extension-api/package.json @@ -0,0 +1,28 @@ +{ + "name": "@pistonite/skybook-extension-api", + "private": true, + "version": "0.0.1", + "description": "TODO", + "homepage": "TODO", + "bugs": { + "url": "TODO" + }, + "license": "MIT", + "author": "Pistonight ", + "files": [ + "src/**/*" + ], + "exports": { + ".": "./src/index.ts", + "./workex": "./src/workex/index.ts", + "./sides/*": "./src/sides/*.ts", + "./interfaces/*": "./src/interfaces/*.ts" + }, + "todo.repository": { + "type": "git", + "url": "https://github.com" + }, + "dependencies": { + "@pistonite/pure": "*" + } +} diff --git a/packages/extension-api/src/.gitignore b/packages/extension-api/src/.gitignore new file mode 100644 index 0000000..52438e2 --- /dev/null +++ b/packages/extension-api/src/.gitignore @@ -0,0 +1,4 @@ +# workex generated files +workex +/interfaces/ +/sides/ diff --git a/packages/extension-api/src/index.ts b/packages/extension-api/src/index.ts new file mode 100644 index 0000000..e82a051 --- /dev/null +++ b/packages/extension-api/src/index.ts @@ -0,0 +1,2 @@ +export * from "./protocol.ts"; +export * from "./types.ts"; diff --git a/packages/extension-api/src/protocol.ts b/packages/extension-api/src/protocol.ts new file mode 100644 index 0000000..0469d7a --- /dev/null +++ b/packages/extension-api/src/protocol.ts @@ -0,0 +1,50 @@ +import { WorkexPromise } from "workex"; + +/** + * API implemented by the extension and called by the application. + * + * @workex:send app + * @workex:recv ext + */ +export interface Extension { + /** + * Notify the extension that the dark mode preference has changed. + * + * The extension can update the theme based on this event + */ + onDarkModeChanged(dark: boolean): WorkexPromise; + + /** + * Notify the extension that the locale perference has changed. + * + * The locale string is one of the supported locales by the application, + * such as `en-US`, `fr-FR`, etc. + * + * The extension can update the UI strings based on this event. + */ + onLocaleChanged(locale: string): WorkexPromise; + + /** + * Notify the extension that the script has changed. + */ + onScriptChanged(script: string): WorkexPromise; + +} + +/** + * API implemented by the application and called by the extension. + * + * @workex:send ext + * @workex:recv app + */ +export interface Application { + + /** Get the current simulator script. */ + getScript(): WorkexPromise; + + /** Set the simulator script. */ + setScript(script: string): WorkexPromise; + + // /** Get the semantic tokens for the current script */ + // provideSemanticTokens(start: number, end: number): WorkexPromise; +} diff --git a/packages/extension-api/src/types.ts b/packages/extension-api/src/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/extension-api/tsconfig.json b/packages/extension-api/tsconfig.json new file mode 100644 index 0000000..1f7887e --- /dev/null +++ b/packages/extension-api/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../config/tsconfig-vite-app.json", + "include": ["src"], +} diff --git a/packages/intwc/.gitignore b/packages/intwc/.gitignore new file mode 100644 index 0000000..293dd6e --- /dev/null +++ b/packages/intwc/.gitignore @@ -0,0 +1,2 @@ +/node_modules +*.gen.ts diff --git a/packages/intwc/README.md b/packages/intwc/README.md new file mode 100644 index 0000000..261171e --- /dev/null +++ b/packages/intwc/README.md @@ -0,0 +1,33 @@ +# intwc +I-Need-To-Write-Code + +Code editor wrapper component for writing code in a browser for my projects. + +Currently, it only supports Vite + React. + +## Features +- Syntax highlighting and validation +- TypeScript custom type library and type checking +- Support for a custom language: + - semantic token + - completion + - diagnostics + - definition +- Tuned Cattppuccin theme for supported languages +- Vim and Emacs mode + +## Non-features +- Project-wide TypeScript language features (e.g. go to definition, find references) +- ES Modules +- Run sandboxed TypeScript code (will be another project) + +## Tech +Under the hood, this project uses [monaco-editor](https://github.com/microsoft/monaco-editor), +which is VS Code with shims to run in a browser. This ensures +the code editor has all the basic features, including accessbility. +This project does not use the existing wrappers/replacements for monaco-editor that adds support +for VSCode API. As a result, it has much less complexity at the cost +of not having the full feature and extension support of VS Code. + +## TODO +- [ ] Add multiple file support diff --git a/packages/intwc/Taskfile.yml b/packages/intwc/Taskfile.yml new file mode 100644 index 0000000..7fffe4b --- /dev/null +++ b/packages/intwc/Taskfile.yml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + build: + cmds: + - deno generateThemes.ts > src/theme/themes.gen.ts diff --git a/packages/intwc/generateThemes.ts b/packages/intwc/generateThemes.ts new file mode 100644 index 0000000..356a8c1 --- /dev/null +++ b/packages/intwc/generateThemes.ts @@ -0,0 +1,211 @@ +// To enable maximum tree-shaking, we don't depend on catppuccin at runtime. Instead, +// we generate the themes at build time and only reference the colors we need +// +// Output is written to stdout, so any engine that supports TypeScript can run this script +import { ColorFormat, flavors } from "@catppuccin/palette"; + +function opacity(color: ColorFormat, alpha: number) { + const alphaInt = Math.max(Math.min(Math.floor(alpha * 255), 255), 0); + const alphaHex = alphaInt.toString(16).padStart(2, "0"); + return color.hex + alphaHex; +} +function createTokenStyle(tokens: string[], style: Record) { + return tokens.map(token => ({ + token, + ...style + })); +} + +function createCommentTokenStyle(style: Record) { + return createTokenStyle(["comment"], style); +} + +function createPunctuationTokenStyle(style: Record) { + return createTokenStyle([ + "punctuation", + "delimiter", + "meta.brace", + ], style); +} + +function createKeywordTokenStyle(style: Record) { + return createTokenStyle([ + "keyword", + ], style); +} + +function createOperatorTokenStyle(style: Record) { + return createTokenStyle([ + "keyword.operator", + "operator", + ], style); +} + +function createVariableTokenStyle(style: Record) { + return createTokenStyle([ + "variable", + "variable.parameter", + ], style); +} + +function createVariableLibraryTokenStyle(style: Record) { + return createTokenStyle([ + "variable.language", + ], style); +} + +function createVariableConstTokenStyle(style: Record) { + return createTokenStyle([ + "variable.readonly", + ], style); +} + +function createFunctionTokenStyle(style: Record) { + return createTokenStyle([ + "support.function", + "function" + ], style); +} + +function createMacroTokenStyle(style: Record) { + return createTokenStyle([ + "meta.macro", + ], style); +} + +function createTypeTokenStyle(style: Record) { + return createTokenStyle([ + "class", + "type", + "namespace", + "support.type", + ], style); +} + +function createLiteralConstantTokenStyle(style: Record) { + return createTokenStyle([ + "constant", + "number", + ], style); +} + +function createLiteralStringTokenStyle(style: Record) { + return createTokenStyle([ + "string", + ], style); +} + +function createLiteralRegExpTokenStyle(style: Record) { + return createTokenStyle([ + "string.regexp", + "regexp", + ], style); +} + +function createSourceTokenStyle(style: Record) { + return createTokenStyle([ + "source", + ], style); +} + +function createEscapeTokenStyle(style: Record) { + return createTokenStyle([ + "constant.character.escape", + "string.escape", + ], style); +} + + + +function createDarkTheme() { + const mocha = flavors.mocha.colors; + const frappe = flavors.frappe.colors; + return { + editorColors: { + "foreground": mocha.text.hex, + "descriptionForeground": mocha.text.hex, + "errorForeground": mocha.red.hex, + "selection.background": opacity(mocha.text, 0.1), + "focusBorder": mocha.lavender.hex, + + "editor.background": mocha.base.hex, + "editor.foreground": mocha.text.hex, + "editorWidget.background": frappe.base.hex, + "editorWidget.border": frappe.mantle.hex, + "editorCursor.foreground": mocha.rosewater.hex, + "editorIndentGuide.background": mocha.surface0.hex, + "editorBracketMatch.background": opacity(mocha.text, 0.1), + "editorBracketMatch.border": mocha.peach.hex, + "editorError.foreground": mocha.red.hex, + "editorWarning.foreground": mocha.yellow.hex, + "editorMarkerNagivationError.background": mocha.red.hex, + "editorLineNumber.foreground": mocha.overlay2.hex, + "editorLineNumber.activeForeground": mocha.overlay2.hex, + "editor.lineHighlightBackground": opacity(mocha.text, 0.1), + + "input.background": mocha.mantle.hex, + "input.foreground": mocha.text.hex, + "input.placeholderForeground": mocha.surface0.hex, + }, + tokenColors: [ + ...createCommentTokenStyle({ + foreground: mocha.overlay2.hex, + fontStyle: "italic" + }), + ...createPunctuationTokenStyle({ + foreground: mocha.overlay2.hex + }), + ...createKeywordTokenStyle({ + foreground: mocha.mauve.hex + }), + ...createOperatorTokenStyle({ + foreground: mocha.sapphire.hex + }), + ...createVariableTokenStyle({ + foreground: mocha.lavender.hex + }), + ...createVariableLibraryTokenStyle({ + foreground: mocha.red.hex + }), + ...createVariableConstTokenStyle({ + foreground: mocha.peach.hex + }), + ...createFunctionTokenStyle({ + foreground: mocha.yellow.hex + }), + ...createMacroTokenStyle({ + foreground: mocha.peach.hex + }), + ...createTypeTokenStyle({ + foreground: mocha.blue.hex + }), + ...createLiteralConstantTokenStyle({ + foreground: mocha.peach.hex + }), + ...createLiteralStringTokenStyle({ + foreground: mocha.green.hex + }), + ...createLiteralRegExpTokenStyle({ + foreground: mocha.red.hex + }), + ...createSourceTokenStyle({ + foreground: mocha.text.hex + }), + ...createEscapeTokenStyle({ + foreground: mocha.pink.hex + }), + ] + } as const; +} + +type Theme = ReturnType; + +function emitTheme(ident: string, theme: Theme) { + console.log(`export const ${ident} = ` + JSON.stringify(theme, null, 4) + ";"); +} + + + +emitTheme("DarkTheme", createDarkTheme()); + +console.log("export type Theme = typeof DarkTheme;"); diff --git a/packages/intwc/package.json b/packages/intwc/package.json new file mode 100644 index 0000000..8b00c1f --- /dev/null +++ b/packages/intwc/package.json @@ -0,0 +1,33 @@ +{ + "name": "@pistonite/intwc", + "private": true, + "version": "0.0.1", + "description": "TODO", + "homepage": "TODO", + "bugs": { + "url": "TODO" + }, + "license": "MIT", + "author": "Pistonight ", + "files": [ + "src/**/*" + ], + "exports": { + ".": "./src/index.ts" + }, + "todo.repository": { + "type": "git", + "url": "https://github.com" + }, + "dependencies": { + "@pistonite/pure": "*", + "@pistonite/monaco-typescript-contrib": "0.0.1", + "monaco-editor-contrib": "0.52.2" + }, + "devDependencies": { + "@catppuccin/palette": "^1.7.1", + "@types/react": "^18.3.16", + "react": "^18.3.1", + "vite": "^5.4.11" + } +} diff --git a/packages/intwc/src/CodeEditor.tsx b/packages/intwc/src/CodeEditor.tsx new file mode 100644 index 0000000..1e5dd4f --- /dev/null +++ b/packages/intwc/src/CodeEditor.tsx @@ -0,0 +1,31 @@ +import { useEffect, useState } from "react"; + +import { CodeEditorApi, EditorState } from "./EditorState.ts"; + +export type CodeEditorProps = { + /** + * Callback when the editor is first created. You can return + * a callback to be called when the editor is about to be destroyed. + * + * Use this to open initial file(s) + */ + onCreated?: (api: CodeEditorApi) => (() => void) | void; +} & React.HTMLAttributes; + +export const CodeEditor: React.FC = ({onCreated, ...props}) => { + const [ref, setRef] = useState(null); + + useEffect(() => { + if (!ref) { + return; + } + const editor = new EditorState(ref); + const cleanup = onCreated?.(editor); + return () => { + cleanup?.(); + editor.dispose(); + }; + }, [ ref]); + + return (
); +}; diff --git a/packages/intwc/src/EditorState.ts b/packages/intwc/src/EditorState.ts new file mode 100644 index 0000000..9d3de5a --- /dev/null +++ b/packages/intwc/src/EditorState.ts @@ -0,0 +1,168 @@ +// import { isDark } from '@pistonite/pure/pref'; +import * as monaco from 'monaco-editor-contrib'; +import { getProvideMarkersCallback } from './language/MarkerProviderRegistry'; +import { EditorOption } from './types.ts'; + + +export type CodeEditorApi = { + /** Get the list of opened files */ + getFiles: () => string[]; + + /** Get the current opened file in the editor */ + getCurrentFile: () => string | undefined; + /** + * Switch to the given file in the editor + * + * Does nothing if the file doesn't exist in the opened files + */ + switchToFile: (filename: string) => void; + /** + * Close the given file in the editor + * + * Does nothing if the file doesn't exist in the opened files + */ + closeFile: (filename: string) => void; + /** + * Open a new file and switch to it in the editor. + * + * If the file is already opened, just switch to it. + */ + openFile(filename: string, content: string, language: string): void; + + /** Get the content of the given file */ + getFileContent: (filename: string) => string; + + /** Set the content of the given file in the editor */ + setFileContent: (filename: string, content: string) => void; + + /** Subscribe to when files are changed */ + subscribe: (callback: (filename: string) => void) => () => void; +} + +let editorOptions: EditorOption = { + options: {}, +} + +export const setEditorOptions = (options: EditorOption) => { + editorOptions = options; +} + +export class EditorState implements CodeEditorApi { + private instance: monaco.editor.IStandaloneCodeEditor; + private models: Map; + private extraCleanup: () => void; + private subscribers: ((filename: string) => void)[]; + + constructor(node: HTMLDivElement) { + this.models = new Map(); + this.subscribers = []; + + this.instance = monaco.editor.create(node, { + autoDetectHighContrast: true, + wordBasedSuggestions: "off", + bracketPairColorization: { + enabled: false, + independentColorPoolPerBracketType: false, + }, + "semanticHighlighting.enabled": true, + automaticLayout: true, + tabSize: 2, + insertSpaces: true, + ...editorOptions.options, + }); + + this.extraCleanup = () => { + + }; + } + + /** Dispose the editor */ + public dispose() { + this.extraCleanup(); + this.instance.setModel(null); + for (const model of this.models.values()) { + model.dispose(); + } + this.instance.dispose(); + } + + public getFiles(): string[] { + return Array.from(this.models.keys()); + } + + public getCurrentFile(): string | undefined { + return this.instance.getModel()?.uri.path; + } + + public closeFile(filename: string) { + const model = this.models.get(filename); + if (model) { + if (model === this.instance.getModel()) { + this.instance.setModel(null); + } + model.dispose(); + this.models.delete(filename); + } + } + + public getFileContent(filename: string): string { + const model = this.models.get(filename); + if (model) { + console.log("get", model.getValue()); + return model.getValue(); + } + return ""; + } + + public setFileContent(filename: string, content: string) { + const model = this.models.get(filename); + if (model && model.getValue() !== content) { + console.log(model.getValue(), content); + // model.setValue(content); + } + } + + public subscribe(callback: (filename: string) => void): () => void { + this.subscribers.push(callback); + return () => { + const index = this.subscribers.indexOf(callback); + if (index !== -1) { + this.subscribers.splice(index, 1); + } + }; + } + + + public openFile(filename: string, content: string, language: string) { + const model = this.models.get(filename); + if (!model) { + const model = monaco.editor.createModel(content, language, monaco.Uri.file(filename)); + const provideMarkersCallback = getProvideMarkersCallback(); + // there can be only one change event listener, so this is not exposed + model.onDidChangeContent(() => { + console.log("changed", model.getValue()); + provideMarkersCallback(model); + this.subscribers.forEach(subscriber => subscriber(filename)); + }); + model.updateOptions({ + tabSize: 2, + indentSize: 2, + insertSpaces: true, + trimAutoWhitespace: true, + bracketColorizationOptions: { + enabled: false, + independentColorPoolPerBracketType: false, + } + }); + this.models.set(filename, model); + } + this.switchToFile(filename); + } + + public switchToFile(filename: string) { + const model = this.models.get(filename); + if (model) { + this.instance.setModel(model); + } + } +} diff --git a/packages/intwc/src/index.ts b/packages/intwc/src/index.ts new file mode 100644 index 0000000..0092a5a --- /dev/null +++ b/packages/intwc/src/index.ts @@ -0,0 +1,6 @@ +export * from './EditorState.ts'; +export * from './CodeEditor.tsx'; +export * from "./types.ts"; +export * from "./init.ts"; +export * from "./language/LanguageClient.ts"; + diff --git a/packages/intwc/src/init.ts b/packages/intwc/src/init.ts new file mode 100644 index 0000000..8a57419 --- /dev/null +++ b/packages/intwc/src/init.ts @@ -0,0 +1,122 @@ +import * as monaco from 'monaco-editor-contrib'; + +import { initPreference } from "./preference.ts"; +import { InitOption } from "./types.ts"; +import { initThemes } from './theme'; + +import { patchMonacoTypeScript } from "@pistonite/monaco-typescript-contrib"; +import { registerMarkerProvider } from './language/MarkerProviderRegistry.ts'; +import { setEditorOptions } from './EditorState.ts'; + +export function initCodeEditor({preferences, language, editor}: InitOption) { + initPreference(preferences || {}); + + const {typescript, json, css, html, custom} = language || {}; + + // initialize monaco + window.MonacoEnvironment = { + getWorker: async (_, label: string) => { + if (typescript && (label === "typescript" || label === "javascript" || label==="tsx" || label==="jsx")) { + const TypeScriptWorker = (await import('monaco-editor-contrib/esm/vs/language/typescript/ts.worker.js?worker')).default; + return new TypeScriptWorker(); + } + if (json && (label === "json"|| label === "jsonc")) { + const JsonWorker = (await import('monaco-editor-contrib/esm/vs/language/json/json.worker.js?worker')).default; + return new JsonWorker(); + } + if (css && (label === "css"|| label === "scss" || label === "sass" || label === "less")) { + const CssWorker = (await import('monaco-editor-contrib/esm/vs/language/css/css.worker.js?worker')).default; + return new CssWorker(); + } + if (html && (label === "html"|| label === "htm")) { + const HtmlWorker = (await import('monaco-editor-contrib/esm/vs/language/html/html.worker.js?worker')).default; + return new HtmlWorker(); + } + const EditorWorker = (await import('monaco-editor-contrib/esm/vs/editor/editor.worker.js?worker')).default; + return new EditorWorker(); + } + }; + + initThemes(); + + // initialize TypeScript options + if (typescript) { + + const dom = typescript.dom ?? true; + monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + target: monaco.languages.typescript.ScriptTarget.ESNext, + lib: dom ? undefined : ["esnext"], + noEmit: true, + strict: true, + // jsx: "preserve", + noUnusedLocals: true, + noUnusedParameters: true, + noFallthroughCasesInSwitch: true, + }); + + if (typescript.extraLibs) { + typescript.extraLibs.forEach((lib) => { + monaco.languages.typescript.typescriptDefaults.addExtraLib(lib.content, `file:///_lib_${lib.name}.ts`); + }); + } + + patchMonacoTypeScript({ + semanticTokensMaxLength: -1 + }); + } + + if (custom) { + custom.forEach((client) => { + console.log("registering", client.getId(), client); + const id = client.getId(); + monaco.languages.register({ + id , + extensions: client.getExtensions?.() + }); + const tokenizer = client.getTokenizer?.(); + if (tokenizer) { + monaco.languages.registerTokensProviderFactory(id, { + create: () => tokenizer + }); + // monaco.languages.setMonarchTokensProvider(id, tokenizer); + } + const configuration = client.getConfiguration?.(); + if (configuration) { + monaco.languages.setLanguageConfiguration(id, configuration); + } + + const getLegend = client.getSemanticTokensLegend?.bind(client); + const provideDocumentRangeSemanticTokens = client.provideDocumentRangeSemanticTokens?.bind(client); + + if (getLegend && provideDocumentRangeSemanticTokens) { + monaco.languages.registerDocumentRangeSemanticTokensProvider(id, { + getLegend, + provideDocumentRangeSemanticTokens + }); + } + + const provideMarkers = client.provideMarkers?.bind(client); + if (provideMarkers) { + registerMarkerProvider(id, { + owner: client.getMarkerOwner?.() || id, + provide: provideMarkers + }); + } + + const provideCompletionItems = client.provideCompletionItems?.bind(client); + if (provideCompletionItems) { + const completionTriggerCharacters = client.getCompletionTriggerCharacters?.(); + const resolveCompletionItem = client.resolveCompletionItem?.bind(client); + monaco.languages.registerCompletionItemProvider(id, { + triggerCharacters: completionTriggerCharacters, + provideCompletionItems, + resolveCompletionItem + }); + } + }); + } + + if (editor) { + setEditorOptions(editor); + } +} diff --git a/packages/intwc/src/language/LanguageClient.ts b/packages/intwc/src/language/LanguageClient.ts new file mode 100644 index 0000000..84068bd --- /dev/null +++ b/packages/intwc/src/language/LanguageClient.ts @@ -0,0 +1,46 @@ +import * as monaco from 'monaco-editor-contrib'; + + +export type TextModel = monaco.editor.ITextModel; +export type MarkerData = monaco.editor.IMarkerData; +export type Range = monaco.Range; +export type Position = monaco.Position; +export type CancellationToken = monaco.CancellationToken; +export type SemanticTokensProvider = monaco.languages.DocumentRangeSemanticTokensProvider; +export type SemanticTokensLegend = monaco.languages.SemanticTokensLegend; +export type SemanticTokensResult = monaco.languages.ProviderResult; +export type CompletionItemProvider = monaco.languages.CompletionItemProvider; +export type CompletionItem = monaco.languages.CompletionItem; +export type CompletionList = monaco.languages.CompletionList; +export type CompletionResult = monaco.languages.ProviderResult; +export type MarkerResult = monaco.languages.ProviderResult; + + +export type LanguageTokenizer = monaco.languages.IMonarchLanguage; +export type LanguageConfiguration = monaco.languages.LanguageConfiguration; + +export type LanguageClient = { + /** Get the language id */ + getId: () => string; + getExtensions?: () => string[]; + /** Get the tokenizer to register on initialization */ + getTokenizer?: () => LanguageTokenizer; + /** Get the configuration to register on initialization */ + getConfiguration?: () => LanguageConfiguration; + + getSemanticTokensLegend?: () => SemanticTokensLegend; + + provideDocumentRangeSemanticTokens?: (model: TextModel, range: Range, token: CancellationToken) => SemanticTokensResult; + + getMarkerOwner?: () => string; + + provideMarkers?: (model: TextModel) => MarkerResult; + + getCompletionTriggerCharacters?: () => string[]; + + provideCompletionItems?: (model: TextModel, position: Position, context: monaco.languages.CompletionContext, token: CancellationToken) => CompletionResult; + + resolveCompletionItem?: (item: CompletionItem, token: CancellationToken) => CompletionItem, +}; + +monaco.languages.registerCompletionItemProvider diff --git a/packages/intwc/src/language/MarkerProviderRegistry.ts b/packages/intwc/src/language/MarkerProviderRegistry.ts new file mode 100644 index 0000000..cde8869 --- /dev/null +++ b/packages/intwc/src/language/MarkerProviderRegistry.ts @@ -0,0 +1,49 @@ +import * as monaco from 'monaco-editor-contrib'; +import { serial } from '@pistonite/pure/sync'; + +import type { MarkerResult, TextModel } from "./LanguageClient.ts"; + +export type MarkerProvider = { + owner: string; + provide: (model: TextModel, checkCancel: () => void) => MarkerResult; +}; +const registeredProviders = new Map(); + +export const registerMarkerProvider = (languageId: string, provider: MarkerProvider) => { + const providers = registeredProviders.get(languageId); + if (!providers) { + registeredProviders.set(languageId, [provider]); + return; + } + providers.push(provider); +} + +const provideMarkersCallback = + serial({ + fn: (checkCancel) => (model: TextModel) => { + return provideMarkers(model, checkCancel); + } + }); + +export const getProvideMarkersCallback = (): (model: TextModel) => void => { + return provideMarkersCallback; +} + +const provideMarkers = async (model: TextModel, checkCancel: () => void) => { + const languageId = model.getLanguageId(); + const providers = registeredProviders.get(languageId); + if (!providers) { + return []; + } + const length = providers.length; + for (let i = 0; i < length; i++) { + const provider = providers[i]; + const markers = await provider.provide(model, checkCancel); + checkCancel(); + if (markers) { + monaco.editor.setModelMarkers(model, provider.owner, markers); + } + } +} + + diff --git a/packages/intwc/src/preference.ts b/packages/intwc/src/preference.ts new file mode 100644 index 0000000..d22f54e --- /dev/null +++ b/packages/intwc/src/preference.ts @@ -0,0 +1,78 @@ +import { useSyncExternalStore } from "react"; +import { persist } from "@pistonite/pure/sync"; + +import { InputMode, Preference, PreferenceOption } from "./types.ts"; + +const getDefaultPreference = (): Preference => { + return { + inputMode: "code" + }; +} +const deserializePreference = (value: string): Preference => { + try { + return validatePreference(JSON.parse(value)); + } catch { + return getDefaultPreference(); + } +} + +const validatePreference = (obj: unknown): Preference => { + if (!obj || typeof obj !== "object") { + return getDefaultPreference(); + } + let inputMode: InputMode = "code"; + if ("inputMode" in obj) { + const value = obj.inputMode; + if (value === "vim" || value === "emacs") { + inputMode = value; + } + } + return { + ...getDefaultPreference(), + inputMode, + } +} + +const preference = persist({ + storage: localStorage, + initial: getDefaultPreference(), + key: "Intwc.Preference", + deserialize: deserializePreference, +}); + +export const initPreference = ({persist, defaults}: PreferenceOption) => { + let value: Preference = { + ...getDefaultPreference(), + ...defaults, + } + if (persist) { + preference.init(value); + } else { + preference.disable(); + preference.set(value); + } +} + +export const addPreferenceSubscriber = (subscriber: (preference: Preference) => void + , notifyImmediately?: boolean +): () => void => { + return preference.subscribe(subscriber, notifyImmediately); +} + +export function getPreference(): Preference { + return preference.get(); +} + +export const setPreference = (newPreference: Partial) => { + const newPreferenceMerged = { + ...preference.get(), + ...newPreference, + }; + preference.set(newPreferenceMerged); +} + +export function useInputMode(): InputMode { + const preference = useSyncExternalStore(addPreferenceSubscriber, getPreference); + return preference.inputMode; +} + diff --git a/packages/intwc/src/theme/index.ts b/packages/intwc/src/theme/index.ts new file mode 100644 index 0000000..a989352 --- /dev/null +++ b/packages/intwc/src/theme/index.ts @@ -0,0 +1,19 @@ +import * as monaco from 'monaco-editor-contrib'; + +import { DarkTheme, type Theme } from './themes.gen.ts'; + +export const initThemes = () => { + defineTheme("intwc-dark", "vs-dark", DarkTheme); + + monaco.editor.setTheme("intwc-dark"); +} + +const defineTheme = (name: string, base: "vs" | "vs-dark", theme: Theme) => { + monaco.editor.defineTheme(name, { + base, + inherit: true, + colors: theme.editorColors, + rules: theme.tokenColors, + }); +} + diff --git a/packages/intwc/src/types.ts b/packages/intwc/src/types.ts new file mode 100644 index 0000000..49be318 --- /dev/null +++ b/packages/intwc/src/types.ts @@ -0,0 +1,97 @@ +import * as monaco from "monaco-editor-contrib"; +import type { LanguageClient } from "./language/LanguageClient.ts"; + +/** Option to pass in to init */ +export type InitOption = { + /** + * Preferences for the editor + */ + preferences?: PreferenceOption; + + /** + * Language support configurations + */ + language?: LanguageOption; + + /** + * Option for the editor + */ + editor?: EditorOption; +} + +export type PreferenceOption = { + /** If the preference should be persisted to and loaded from localStorage */ + persist?: boolean; + + /** + * Override the default preference + * + * These will not be applied to the persisted preference + */ + defaults?: Partial; +} + +export type Preference = { + /** + * Input mode for the editor, defaults to "code" + */ + inputMode: InputMode; +} + +export type LanguageOption = { + /** + * TypeScript Configuration + * + * If this is not specified, TypeScript features will not be enabled + */ + typescript?: TSOption; + + /** If JSON language support should be enabled */ + json?: boolean; + + /** If CSS language support should be enabled */ + css?: boolean; + + /** If HTML language support should be enabled */ + html?: boolean; + + /** Custom language support */ + custom: LanguageClient[]; +} + +export type EditorOption = { + /** + * Options used when constructing the editor + * + * These are added on top of the defaults provided by this wrapper + */ + options: monaco.editor.IEditorOptions & monaco.editor.IGlobalEditorOptions +} + +export type TSOption = { + /** + * If DOM API should be enabled for type checking + * + * Default is true + */ + dom?: boolean; + /** + * Extra libraries to load + */ + extraLibs?: TSExtraLib[]; +}; + +export type TSExtraLib = { + /** + * The library name. This is used to make the file uri. + * For example, if the name is "foo", the file uri will + * be "_lib_foo.ts" + */ + name: string, + /** The type definition file content */ + content: string +} + + +/** Input mode of the editor */ +export type InputMode = "code" | "vim" | "emacs"; diff --git a/packages/intwc/tsconfig.json b/packages/intwc/tsconfig.json new file mode 100644 index 0000000..ddc7ff6 --- /dev/null +++ b/packages/intwc/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + "types": ["vite/client"], + }, + "include": ["src"] +} diff --git a/packages/item-animated/.gitignore b/packages/item-animated/.gitignore new file mode 100644 index 0000000..084490d --- /dev/null +++ b/packages/item-animated/.gitignore @@ -0,0 +1,9 @@ +/target +/venv +/video +*.webp +*.mp4 +*.mkb +*.exe +*.lock +*.png diff --git a/packages/item-animated/Cargo.toml b/packages/item-animated/Cargo.toml new file mode 100644 index 0000000..7b7d4c6 --- /dev/null +++ b/packages/item-animated/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "skybook-item-animated-encode" +version = "0.0.0" +edition = "2021" +description = "Encoder for animated icons" + +[dependencies] +anyhow = "1.0.95" +clap = { version = "4.5.23", features = ["derive"] } +image = "0.25.5" +serde = { version = "1.0.216", features = ["derive"] } +serde_yaml_ng = "0.10.0" +webp-animation = { version = "0.9.0", features = ["image"] } + +[[bin]] +name = "skybook-item-animated-encode" +path = "encode.rs" + diff --git a/packages/item-animated/Taskfile.yml b/packages/item-animated/Taskfile.yml new file mode 100644 index 0000000..bba4297 --- /dev/null +++ b/packages/item-animated/Taskfile.yml @@ -0,0 +1,34 @@ +version: '3' + +tasks: + pull-priv: + desc: Pull private assets for the package. Requires gcloud access + cmds: + - rm -rf video + - mkdir -p video + - gcloud storage cp -r gs://ist-private/video . + + decode: + desc: Decode the object + cmds: + - python decode.py {{.CLI_ARGS}} + + encode: + desc: Encode the object + cmds: + - cargo run --release -- {{.CLI_ARGS}} + + push: + desc: Push generated files. Requires gcloud access + cmds: + # The square ones are included in the sprite sheet (/Item) + - gcloud storage cp target/encode/Obj_DungeonClearSeal.png gs://ist-private/icons/Item + - gcloud storage cp target/encode/Obj_DLC_HeroSeal_*.png gs://ist-private/icons/Item + - gcloud storage cp target/encode/Obj_WarpDLC.png gs://ist-private/icons/Item + - gcloud storage cp target/encode/Obj_HeroSoul_*_Disabled.png gs://ist-private/icons/Item + - gcloud storage cp target/encode/Obj_DLC_HeroSoul_*_Disabled.png gs://ist-private/icons/Item + # # Activated abilities are not regular sized, so cannot be in sprite sheet + - gcloud storage cp target/encode/Obj_HeroSoul_*.png gs://ist-private/icons/SP/Item + - gcloud storage cp target/encode/Obj_DLC_HeroSoul_*.png gs://ist-private/icons/SP/Item + # # Put WebPs there as well + - gcloud storage cp target/encode/*.webp gs://ist-private/icons/SP/Item diff --git a/packages/item-animated/config.yaml b/packages/item-animated/config.yaml new file mode 100644 index 0000000..61377e3 --- /dev/null +++ b/packages/item-animated/config.yaml @@ -0,0 +1,150 @@ +encoder: + # "Normal" input frame size - match the decoder config + base_dimension: 118 + # Target frame size. If size == base then output == target + target_dimension: 64 + + # These values are optimized for size at 64x64 + # while still looking good + + # range: [0 = off .. 100 = strongest] + # higher value will be smoother + filter_strength: 0 + # range: [0 = off .. 7 = least sharp] + filter_sharpness: 0 + # 0 - none, 1 - fast, 2 - best + alpha_filtering: 2 + # Between 0 (smallest size) and 100 (lossless). + alpha_quality: 50 + # number of entropy-analysis passes (in [1..10]) + pass: 10 + # overall quality + quality: 90 + # Quality/speed trade-off (0=fast, 6=slower-better) + method: 6 + # 1-4 + segments: 4 + +decoder: + measurements: + border_to_first_inner_left: 187 + border_to_first_inner_top: 335 + cell_offset: 147 + base_size: 118 + background_threshold: 0x10 + orb_erase_x: + width: 22 + height: 20 + orb_erase_digit: + left: 22 + bottom: 28 + width: 18 + height: 23 + erase_threshold: 72 + erase_context: 1 + fixup_left: 41 # color used to "fix" the erased part + fixup_bottom: 23 + fixup_weight: 0.8 + fixup_iteration: 2 + fixup_context: 1 + border_erase_threshold: 0x40 + profiles: + orb: + frames: 240 + top_expand: 0 + erase_count: true + travel: + frames: 960 + top_expand: 0 + erase_count: false + souloff: + frames: 240 + top_expand: 0 + erase_count: false + soulon: + frames: 240 + top_expand: 21 + erase_count: false + souloffdlc: + frames: 240 + top_expand: 0 + erase_count: false + souldlc: + frames: 240 + top_expand: 40 + erase_count: false + top_clean: 9 + side_expand: 3 + + +objects: + orb:Obj_DungeonClearSeal: + file: video/spirit_orb.mp4 + row_col: [3, 3] + orb:Obj_DLC_HeroSeal_Gerudo: + file: video/naboris_orb.mp4 + row_col: [2, 1] + orb:Obj_DLC_HeroSeal_Goron: + file: video/rudania_orb.mp4 + row_col: [2, 2] + orb:Obj_DLC_HeroSeal_Rito: + file: video/medoh_orb.mp4 + row_col: [1, 4] + orb:Obj_DLC_HeroSeal_Zora: + file: video/ruta_orb.mp4 + row_col: [2, 0] + travel:Obj_WarpDLC: + file: video/travel.mp4 + row_col: [2, 3] + souloff:Obj_HeroSoul_Gerudo_Disabled: + file: video/soul.mp4 + row_col: [0, 4] + souloff:Obj_HeroSoul_Goron_Disabled: + file: video/soul.mp4 + row_col: [1, 1] + souloff:Obj_HeroSoul_Rito_Disabled: + file: video/soul.mp4 + row_col: [0, 2] + souloff:Obj_HeroSoul_Zora_Disabled: + file: video/soul.mp4 + row_col: [1, 0] + soulon:Obj_HeroSoul_Gerudo: + file: video/soulon.mp4 + row_col: [0, 4] + soulon:Obj_HeroSoul_Goron: + file: video/soulon.mp4 + row_col: [1, 1] + soulon:Obj_HeroSoul_Rito: + file: video/soulon.mp4 + row_col: [0, 2] + soulon:Obj_HeroSoul_Zora: + file: video/soulon.mp4 + row_col: [1, 0] + souloffdlc:Obj_DLC_HeroSoul_Gerudo_Disabled: + file: video/souloffdlc.mp4 + row_col: [1, 4] + souloffdlc:Obj_DLC_HeroSoul_Goron_Disabled: + file: video/souloffdlc.mp4 + row_col: [1, 2] + souloffdlc:Obj_DLC_HeroSoul_Rito_Disabled: + file: video/souloffdlc.mp4 + row_col: [1, 3] + souloffdlc:Obj_DLC_HeroSoul_Zora_Disabled: + file: video/souloffdlc.mp4 + row_col: [0, 1] + souldlc:Obj_DLC_HeroSoul_Gerudo: + file: video/souldlc.mp4 + row_col: [1, 4] + top_clean_frame: 96 + souldlc:Obj_DLC_HeroSoul_Goron: + file: video/souldlc.mp4 + row_col: [1, 2] + top_clean_frame: 96 + souldlc:Obj_DLC_HeroSoul_Rito: + file: video/souldlc.mp4 + row_col: [1, 3] + top_clean_frame: 96 + souldlc:Obj_DLC_HeroSoul_Zora: + file: video/souldlc2.mp4 # had to take another one because first row are clipped off + row_col: [1, 0] + top_clean_frame: 0 diff --git a/packages/item-animated/decode.py b/packages/item-animated/decode.py new file mode 100644 index 0000000..c249b07 --- /dev/null +++ b/packages/item-animated/decode.py @@ -0,0 +1,379 @@ +""" + Step 2: Decode video into frames + Usage: python decode.py ... + + This will decode the video and crop the item in the row and col (0-based) + + Outputs are in target/decode//frame_X.png + + Check the quality of the frames before preceeding +""" + + +import cv2 +import os +import sys +import shutil +import yaml +import multiprocessing +import json + +def load_config(): + home = os.path.dirname(__file__) + config = os.path.join(home, "config.yaml") + with open(config, "r", encoding="utf-8") as f: + return yaml.safe_load(f) + +def main(): + objects = sys.argv[1:] + expanded_objects = set() + + home = os.path.dirname(__file__) + + config = load_config() + if not objects: + objects = ["*"] + for obj in objects: + if obj.endswith("*"): + prefix = obj[:-1] + for key in config["objects"]: + profile, name = key.split(":", 1) + if not prefix or name.startswith(prefix): + expanded_objects.add((profile, name)) + else: + for key in config["objects"]: + profile, name = key.split(":", 1) + if name == obj or profile == obj: + expanded_objects.add((profile, name)) + + args = [] + for profile, name in expanded_objects: + object_config = config["objects"][profile+":"+name] + video_file = object_config["file"] + [row, col] = object_config["row_col"] + profile_data = config["decoder"]["profiles"][profile] + top_expand = profile_data["top_expand"] + expected_frame_count = profile_data["frames"] + erase_count = profile_data["erase_count"] + side_expand = 0 + if "side_expand" in profile_data: + side_expand = profile_data["side_expand"] + top_clean = 0 + if "top_clean" in profile_data: + top_clean = profile_data["top_clean"] + top_clean_frame = -1 + if "top_clean_frame" in object_config: + top_clean_frame = object_config["top_clean_frame"] + args.append((config, video_file, profile, name, row, col, top_expand, expected_frame_count, erase_count, side_expand, top_clean, top_clean_frame)) + + frame_args = [] + for config, _, _, name, _, _, top_expand, frame_count, erase_count, side_expand, top_clean, _ in args: + output_dir = os.path.join(home, "target", "decode", name) + for i in range(frame_count): + frame_path = os.path.join(output_dir, f"frame_{i}.png") + frame_args.append((config, frame_path, i, name, erase_count, top_expand, side_expand, top_clean)) + + with multiprocessing.Pool() as pool: + # python is pretty limited and it's not worth to optimize here + # just decode frames first, then fix frames + for _ in pool.imap_unordered(decode_frames_shim, args): + pass + for _ in pool.imap_unordered(fix_frame_shim, frame_args): + pass + + print("all done") + + +def decode_frames_shim(args): + config, video_file, profile, object_name, row, col, top_expand, expected_frame_count, _erase_count, side_expand, top_clean, top_clean_frame = args + decode_frames(config, video_file, profile, object_name, row, col, top_expand, expected_frame_count, side_expand, top_clean, top_clean_frame) +def decode_frames(config, video_file, profile, object_name, row, col, top_expand, expected_frame_count, side_expand, top_clean, top_clean_frame): + print(f"[{video_file}] decoding frames (row={row}, col={col})") + home = os.path.dirname(__file__) + cap = cv2.VideoCapture(os.path.join(home, video_file)) + frame_count = 0 + # Measurements + + decoder = config["decoder"] + measurements = decoder["measurements"] + profile = decoder["profiles"][profile] + BORDER_TO_FIRST_INNER_LEFT = measurements["border_to_first_inner_left"] + BORDER_TO_FIRST_INNER_TOP = measurements["border_to_first_inner_top"] + CELL_OFFSET = measurements["cell_offset"] + BASE_SIZE = measurements["base_size"] + TOP_EXPAND = top_expand + + crop_x = BORDER_TO_FIRST_INNER_LEFT + col * CELL_OFFSET - side_expand + crop_y = BORDER_TO_FIRST_INNER_TOP + row * CELL_OFFSET - TOP_EXPAND + crop_x_end = crop_x + BASE_SIZE + side_expand * 2 + crop_y_end = crop_y + BASE_SIZE + TOP_EXPAND + + output_dir = os.path.join(home, "target", "decode", object_name) + if os.path.exists(output_dir): + shutil.rmtree(output_dir) + os.makedirs(output_dir, exist_ok=True) + try: + while True: + ok, frame = cap.read() + if not ok: + break + + frame_filename = os.path.join(output_dir, f"frame_{frame_count}.png") + cropped = frame[crop_y:crop_y_end, crop_x:crop_x_end] + if frame_count % 30 == 0: + print(f"[{video_file}] saving frame {frame_count}") + cv2.imwrite(frame_filename, cropped) + + if frame_count == top_clean_frame: + # extract clean frame data (y,x)[] + # these are pixels that are not black but need to be set black + clean_frame_data = [] + BACKGROUND_THRESHOLD = measurements["background_threshold"] + _, width, _ = cropped.shape + for y in range(top_clean): + for x in range(width): + (r,g,b) = getrgb(cropped, y, x) + if r >= BACKGROUND_THRESHOLD or g >= BACKGROUND_THRESHOLD or b >= BACKGROUND_THRESHOLD: + clean_frame_data.append((y,x)) + clean_filename = os.path.join(output_dir, f"frame_clean.json") + with open(clean_filename, "w", encoding="utf-8") as clean_file: + json.dump(clean_frame_data, clean_file) + print(f"[{video_file}] saved clean frame data") + + frame_count += 1 + except Exception as e: + cap.release() + raise e + + print(f"[{video_file}] saved {frame_count} frames") + + if frame_count != expected_frame_count: + raise ValueError(f"[{video_file}] expected {expected_frame_count} frames, got {frame_count} frames") + +def fix_frame_shim(args): + config, frame_path, ithframe, object_name, erase_count, top_expand, side_expand, top_clean = args + fix_frame(config, frame_path, ithframe, object_name, erase_count, top_expand, side_expand, top_clean) +def fix_frame(config, frame_path, ithframe, object_name, erase_count, top_expand, side_expand, top_clean): + MEASUREMENTS = config["decoder"]["measurements"] + BACKGROUND_THRESHOLD = MEASUREMENTS["background_threshold"] + + frame = cv2.imread(frame_path) + + def fix_top_clean(frame): + clean_filename = os.path.join(os.path.dirname(frame_path), "frame_clean.json") + with open(clean_filename, "r", encoding="utf-8") as clean_file: + clean_data = json.load(clean_file) + for y, x in clean_data: + setblack(frame, y, x) + + def fix_black(frame): + """Clean up the black pixels""" + height, width, _ = frame.shape + for y in range(height): + for x in range(width): + (r,g,b) = getrgb(frame, y ,x) + if is_black(r, g, b): + setblack(frame, y, x) + BORDER_THRESHOLD = MEASUREMENTS["border_erase_threshold"] + for y in range(top_expand): + for x in range(width): + (r,g,b) = getrgb(frame, y ,x) + if b < BORDER_THRESHOLD and g < BORDER_THRESHOLD and r < BORDER_THRESHOLD: + setblack(frame, y, x) + else: + break + for x in range(width): + x = width - x - 1 + (r,g,b) = getrgb(frame, y ,x) + if b < BORDER_THRESHOLD and g < BORDER_THRESHOLD and r < BORDER_THRESHOLD: + setblack(frame, y, x) + else: + break + if side_expand: + # vertical borders on the sides + for y in range(height): + for x in range(side_expand): + (r,g,b) = getrgb(frame, y ,x) + if b < BORDER_THRESHOLD and g < BORDER_THRESHOLD and r < BORDER_THRESHOLD: + setblack(frame, y, x) + (r,g,b) = getrgb(frame, y ,width - x - 1) + if b < BORDER_THRESHOLD and g < BORDER_THRESHOLD and r < BORDER_THRESHOLD: + setblack(frame, y, width - x - 1) + + + def fix_orb_count(frame): + """Cleans up single digit orb count in the lower left corner""" + height, _, _ = frame.shape + # Delete the "x" + ERASE_X_WIDTH = MEASUREMENTS["orb_erase_x"]["width"] + ERASE_X_HEIGHT = MEASUREMENTS["orb_erase_x"]["height"] + for y in range(height - ERASE_X_HEIGHT, height): + for x in range(0, ERASE_X_WIDTH): + setblack(frame, y, x) + + # Delete the digit + ERASE_DIGIT = MEASUREMENTS["orb_erase_digit"] + ERASE_DIGIT_LEFT = ERASE_DIGIT["left"] + ERASE_DIGIT_BOTTOM = ERASE_DIGIT["bottom"] + ERASE_DIGIT_WIDTH = ERASE_DIGIT["width"] + ERASE_DIGIT_HEIGHT = ERASE_DIGIT["height"] + + # Dim the digit until it's not visible + pixels = erase_digit( + frame, + height - ERASE_DIGIT_BOTTOM, + height - ERASE_DIGIT_BOTTOM + ERASE_DIGIT_HEIGHT, + ERASE_DIGIT_LEFT, + ERASE_DIGIT_LEFT + ERASE_DIGIT_WIDTH, + 1, + 72, + ) + + need_fix_pixels = set() + fix_window = 1 + for (y, x) in pixels: + for yy in range(y-fix_window, y+fix_window+1): + for xx in range(x-fix_window, x+fix_window+1): + (r,g,b) = getrgb(frame, yy, xx) + if not is_black(r,g,b): + need_fix_pixels.add((yy,xx)) + + FIXUP_X = ERASE_DIGIT["fixup_left"] + FIXUP_Y = height - ERASE_DIGIT["fixup_bottom"] + (fix_r, fix_g, fix_b) = getrgb(frame, FIXUP_Y, FIXUP_X) + FIX_WEIGHT = ERASE_DIGIT["fixup_weight"] + def add_fix(ct, tt, fix_c): + return round(float(ct // tt) * (1 - FIX_WEIGHT) + float(fix_c) * FIX_WEIGHT) + ITERATION = ERASE_DIGIT["fixup_iteration"] + FIX_CONTEXT = ERASE_DIGIT["fixup_context"] + for _ in range(ITERATION): + new_pixels = [] # y, x, r, g, b + for (y, x) in need_fix_pixels: + (r, g, b) = getrgb(frame, yy, xx) + rt = 0 + gt = 0 + bt = 0 + tt = 0 + for yy in range(y-FIX_CONTEXT, y+FIX_CONTEXT+1): + for xx in range(x-FIX_CONTEXT,x+FIX_CONTEXT+1): + (r, g, b) = getrgb(frame, yy, xx) + rt += int(r) + gt += int(g) + bt += int(b) + tt += 1 + + r = add_fix(rt, tt, fix_r) + g = add_fix(gt, tt, fix_g) + b = add_fix(bt, tt, fix_b) + new_pixels.append((y, x, r, g, b)) + for (y, x, r,g,b) in new_pixels: + setrgb(frame, y , x,r,g,b) + + + def erase_digit(frame, min_y, max_y, min_x, max_x, context, thres): + """ + Fix pixels in the bound according to luminence + if dimming = True, pixels will be less bright + otherwise will be more bright + black pixels are ignored when un-dimming + """ + touched_pixels = set() + while True: + # (y, x) + pixels = [] + for y in range(min_y, max_y): + for x in range(min_x, max_x): + (r, g, b) = getrgb(frame, y, x) + l = luminence(r, g, b) + if l > thres: + pixels.append((y, x)) + if not pixels: + break + # for each pixel, take the average of its non-matched neighbors- + # (y, x, r, g, b) + new_pixels = [] + for (y, x) in pixels: + # non-black lo lumi + r_tot = 0 + g_tot = 0 + b_tot = 0 + count = 0 + all_count = 0 # non-black low lumi + all_black = True # black + non-black low lumi + + for yy in range(y-context,y+context+1): + for xx in range(x-context,x+context+1): + #if yy == y and xx == x: + # continue + (r, g, b) = getrgb(frame, yy, xx) + l = luminence(r, g, b) + if l <= thres: + all_count += 1 + if is_black(r, g, b): + continue + count += 1 + all_black = False + r_tot += int(r) + g_tot += int(g) + b_tot += int(b) + + if not all_count: + # pixel is surrounded by other pixels + continue + if all_black: + # turn pixel into black as well + new_pixels.append((y, x, 0, 0, 0)) + continue + + if count == 0: + raise Exception("should not happen") + + r = round(r_tot / count) + g = round(g_tot / count) + b = round(b_tot / count) + new_pixels.append((y, x, r, g, b)) + # apply edits + if not new_pixels: + break + + for (y, x, r, g, b) in new_pixels: + touched_pixels.add((y,x )) + setrgb(frame, y, x, r, g, b) + + return touched_pixels + + def luminence(r, g, b): + return 0.299 * r + 0.587 * g + 0.114 * b + + def setrgb(frame, y, x, r, g, b): + if is_black(r,g,b): + setblack(frame,y,x) + else: + frame[y,x]=[b,g,r] + + def is_black(r, g, b): + return r < BACKGROUND_THRESHOLD and g < BACKGROUND_THRESHOLD and b < BACKGROUND_THRESHOLD + + + def setblack(frame, y, x): + frame[y,x]=[0,0,0] + + if top_clean: + fix_top_clean(frame) + if erase_count: + fix_orb_count(frame) + fix_black(frame) + + cv2.imwrite(frame_path, frame) + if ithframe % 30 == 0: + print(f"[{object_name}] fixed-up frame {ithframe}") + +def getrgb(frame, y, x): + (b,g,r) = frame[y, x] + return (r,g,b) + + + +if __name__ == "__main__": + main() + diff --git a/packages/item-animated/encode.rs b/packages/item-animated/encode.rs new file mode 100644 index 0000000..d357e08 --- /dev/null +++ b/packages/item-animated/encode.rs @@ -0,0 +1,263 @@ +//! Step 3: encode frames into image +//! cargo run --release +//! This will find target/decode// and encode the image to target/encode/.webp + +use std::{ + collections::{BTreeMap, BTreeSet}, + path::{Path, PathBuf}, + sync::Arc, +}; + +use clap::Parser; +use image::{ + imageops::{self, FilterType}, + DynamicImage, GenericImage, GenericImageView, Rgba, +}; + +use anyhow::{anyhow, bail}; +use serde::Deserialize; +use serde_yaml_ng::Value; +use webp_animation::{ + AnimParams, ColorMode, Encoder, EncoderOptions, EncodingConfig, EncodingType, + LossyEncodingConfig, +}; + +#[derive(Debug, Deserialize)] +struct Config { + objects: BTreeMap, // the value is unused here + encoder: EncoderProfile, +} +#[derive(Debug, Deserialize)] +struct EncoderProfile { + base_dimension: u32, + target_dimension: u32, + filter_strength: usize, + filter_sharpness: usize, + alpha_filtering: usize, + alpha_quality: usize, + pass: usize, + quality: f32, + method: usize, + segments: usize, +} + +#[derive(Debug, Clone, Parser)] +struct Cli { + objects: Vec, +} + +fn main() -> anyhow::Result<()> { + let mut cli = Cli::parse(); + // load config + let config_file = std::fs::read("config.yaml")?; + let config: Config = serde_yaml_ng::from_slice(&config_file)?; + let mut expanded_objects = BTreeSet::new(); + + // parse inputs + if cli.objects.is_empty() { + cli.objects.push("*".to_string()); + } + for obj in cli.objects { + if let Some(object) = obj.strip_suffix('*') { + if object.is_empty() { + for key in config.objects.keys() { + let name = key.splitn(2, ":").skip(1).next().unwrap(); + expanded_objects.insert(name.to_string()); + } + } else { + for key in config.objects.keys() { + let name = key.splitn(2, ":").skip(1).next().unwrap(); + if name.starts_with(object) { + expanded_objects.insert(name.to_string()); + } + } + } + } else { + for key in config.objects.keys() { + let mut parts = key.splitn(2, ":"); + let profile = parts.next().unwrap(); + let name = parts.next().unwrap(); + if name == obj || profile == obj { + expanded_objects.insert(name.to_string()); + } + } + } + } + + // encode each object + let profile = Arc::new(config.encoder); + let mut handles = Vec::new(); + for object in expanded_objects { + let profile = Arc::clone(&profile); + let handle = + std::thread::spawn(move || encode(&object, &profile).map_err(|x| format!("{x:?}"))); + handles.push(handle); + } + + for handle in handles { + match handle.join() { + Err(_) => {} + Ok(x) => x.map_err(|x| anyhow!(x))?, + } + } + + Ok(()) +} + +fn encode(object: &str, profile: &EncoderProfile) -> anyhow::Result<()> { + println!("input: {object}"); + let frames_dir = Path::new("target").join("decode").join(object); + let output_dir = Path::new("target").join("encode"); + if !output_dir.exists() { + std::fs::create_dir_all(&output_dir)?; + } + let mut output_name = PathBuf::from(frames_dir.file_name().unwrap()); + output_name.set_extension("webp"); + let input_path = frames_dir.join("frame_0.png"); + if !input_path.exists() { + bail!("[{object}] cannot find first frame"); + } + let image = image::open(input_path)?; + let (w, h) = image.dimensions(); + // save the first frame as png in original resolution + let first_frame = process_image(&image, w, h); + let mut output_png = output_name.clone(); + output_png.set_extension("png"); + first_frame.save(output_dir.join(output_png))?; + println!("[{object}] saved first frame"); + + // try to avoid precision loss when converting to target dimension + let ratio = profile.target_dimension as f64 / profile.base_dimension as f64; + let target_w = if w == profile.base_dimension { + profile.target_dimension + } else { + (w as f64 * ratio) as u32 + }; + let target_h = if w == h { + target_w + } else { + (h as f64 * ratio) as u32 + }; + + println!("[{object}] webp dimension will be {target_w}x{target_h}"); + + println!("[{object}] loading and transforming frames..."); + + let mut frame_images = Vec::new(); + for i in 0.. { + let input_path = frames_dir.join(format!("frame_{i}.png")); + if !input_path.exists() { + break; + } + let image = image::open(input_path)?; + let image = process_image(&image, target_w, target_h); + frame_images.push(image); + } + println!( + "[{object}] loaded {} frames, encoding...", + frame_images.len() + ); + + let lossy_config = LossyEncodingConfig { + target_size: 0, // off + target_psnr: 0f32, // off + segments: profile.segments, + sns_strength: 100, + filter_strength: profile.filter_strength, + filter_sharpness: profile.filter_sharpness, + filter_type: 1, + autofilter: true, + alpha_compression: true, + alpha_filtering: profile.alpha_filtering, + alpha_quality: profile.alpha_quality, + pass: profile.pass, + show_compressed: false, + preprocessing: true, + partitions: 0, + partition_limit: 0, + use_sharp_yuv: true, + }; + let encoding_config = EncodingConfig { + encoding_type: EncodingType::Lossy(lossy_config), + quality: profile.quality, + method: profile.method, + }; + let anim_params = AnimParams { + loop_count: 0, // inf + }; + let encoder_options = EncoderOptions { + anim_params, + minimize_size: true, + verbose: false, + color_mode: ColorMode::Rgba, + encoding_config: Some(encoding_config), + ..Default::default() + }; + let mut encoder = Encoder::new_with_options((target_w, target_h), encoder_options)?; + for (i, image) in frame_images.iter().enumerate() { + if i % 30 == 0 { + println!("[{object}] encoding frame {i}"); + } + encoder.add_frame(image.as_bytes(), timestamp(i as u32))?; + } + + let encoded = encoder.finalize(timestamp(frame_images.len() as u32))?; + let size = encoded.len(); + let output_path = output_dir.join(output_name); + std::fs::write(output_path, &*encoded)?; + println!("[{object}] done ({size} bytes)"); + + Ok(()) +} + +fn timestamp(i: u32) -> i32 { + // 30 fps + let whole = i as i32 / 3 * 100; + match i % 3 { + 0 => whole, + 1 => whole + 33, + 2 => whole + 67, + _ => unreachable!(), + } +} + +fn process_image(input: &DynamicImage, target_w: u32, target_h: u32) -> DynamicImage { + let (w, h) = input.dimensions(); + let mut output = DynamicImage::new_rgba8(w, h); + for x in 0..w { + for y in 0..h { + let [r, g, b, _] = input.get_pixel(x, y).0; + let (r, g, b, a) = add_alpha(r, g, b); + output.put_pixel(x, y, Rgba([r, g, b, a])) + } + } + let resized = imageops::resize(&output, target_w, target_h, FilterType::Lanczos3); + resized.into() +} + +fn add_alpha(r: u8, g: u8, b: u8) -> (u8, u8, u8, u8) { + let rf = r as f64; + let gf = g as f64; + let bf = b as f64; + let alpha_weight = (rf * rf + gf * gf + bf * bf).sqrt(); + + // let lumi = 0.299 * r as f64 + 0.587 * g as f64 + 0.114 * b as f64; + let alpha_weight = (alpha_weight / 255.0).min(1.0); + // sqrt to curve it? + let alpha = alpha_weight; //.sqrt(); + + #[inline] + fn fix(x: u8, a: f64) -> u8 { + // since alpha max is 1.0, this should not overflow + // check just in case + let xa = (x as f64 / a).floor(); + if xa > 255.0 { + 255 + } else { + xa as u8 + } + } + + let a = (alpha * 255.0).floor() as u8; + (fix(r, alpha), fix(g, alpha), fix(b, alpha), a) +} diff --git a/packages/item-animated/requirements.txt b/packages/item-animated/requirements.txt new file mode 100644 index 0000000..b3bd165 --- /dev/null +++ b/packages/item-animated/requirements.txt @@ -0,0 +1,2 @@ +opencv-python +pyyaml diff --git a/packages/item-animated/splice.ps1 b/packages/item-animated/splice.ps1 new file mode 100644 index 0000000..0c617b8 --- /dev/null +++ b/packages/item-animated/splice.ps1 @@ -0,0 +1,42 @@ +# Preparation: +# Get the items, go to Ketoh Wawai and go to a spot where it's completely dark, look up, open inventory +# Make sure the cursor is not on or next to any item you want to extract +# Use OBS to record ~1 min video to work with. I have 6000 Kbps +# Then, use a tool like avidemux or mpv to find the timecode to splice from the video +# +# Step 1: Splice +# ./splice.ps1 +# Re-encode the video so each frame correspond to one frame of the animation +# Needs mpv and ffmpeg, args for Nvidia GPU only +# Time code formats are HH:MM:SS.mmm + +$file = $args[0] +$from = $args[1] +$to = $args[2] +$temp = "temp.mp4" +$output = $args[3] + +$from = python tc.py -mt $from +$to = python tc.py -mt $to +while($true) { + $vframes = python tc.py -s $to $from + $duration = python tc.py -at $vframes 3 + ./ffmpeg.exe -y -hwaccel nvdec -hwaccel_output_format cuda -ss $from -i $file -framerate 30 -filter_complex "scale_cuda=1920:1080,hwdownload,format=nv12 [base]" -map "[base]" -c:v h264_nvenc -b:v "6M" -fps_mode passthrough -vframes $vframes -to $duration $temp + mpv $temp --loop=inf --keep-open + $selection = Read-Host "Enter adjustment or empty to stop" + if ("" -eq $selection) { + Write-Output "Final: $from $to" + break + } + $adjustment = $selection -Split ";" + if ("m" -eq $adjustment[2]){ + $from = python tc.py -mat $from $adjustment[0] + $to = python tc.py -mat $to $adjustment[1] + }else{ + $from = python tc.py -at $from $adjustment[0] + $to = python tc.py -at $to $adjustment[1] + } +} + +Move-Item -Path $temp -Destination $output -Force + diff --git a/packages/item-animated/tc.py b/packages/item-animated/tc.py new file mode 100644 index 0000000..694b790 --- /dev/null +++ b/packages/item-animated/tc.py @@ -0,0 +1,170 @@ +import sys +import re +import argparse + +FRAME_PER_SECOND = 30 +MS_PER_SECOND = 1000 +SECOND_PER_MINUTE = 60 +MINUTE_PER_HOUR = 60 + +def is_strh(strh): + # 0123456789abc + # hh:mm:ss.mss + strh = str(strh) + if len(strh) != 12: + return False + return re.search("^[0-9][0-9]+:[0-9][0-9]:[0-9][0-9]\\.[0-9][0-9][0-9]$", strh) is not None + +def is_frame(frame): + return re.search("^-?[0-9]+$", str(frame)) is not None + +def frm_to_strh(frames): + negative = frames < 0 + if negative: + frames = -frames + millisecond_frames = frames % FRAME_PER_SECOND + seconds = (frames - millisecond_frames) / FRAME_PER_SECOND + minute_seconds = seconds % SECOND_PER_MINUTE + minutes = (seconds - minute_seconds) / SECOND_PER_MINUTE + hour_minutes = minutes % MINUTE_PER_HOUR + hours = (minutes - hour_minutes) / MINUTE_PER_HOUR + + rest_millisecond = millisecond_frames % (FRAME_PER_SECOND/10) + hundred_millisecond = (millisecond_frames - rest_millisecond) / (FRAME_PER_SECOND/10) + + if rest_millisecond == 0: + rest_millisecond = 0 + elif rest_millisecond == 1: + rest_millisecond = 33 + else: + rest_millisecond = 67 + + return format_strh(negative, hours, hour_minutes, minute_seconds, hundred_millisecond*100+rest_millisecond) + +def strh_to_frm(strh): + # 0123456789abc + # hh:mm:ss.mss + hours = int(strh[0:2]) + minutes = int(strh[3:5]) + seconds = int(strh[6:8]) + ms_hundred = int(strh[9:10]) + ms_rest = int(strh[10:]) + if ms_rest > 60: + frames = 2 + elif ms_rest>30: + frames = 1 + else: + frames = 0 + frames+=ms_hundred*(FRAME_PER_SECOND/10) + frames+=seconds*FRAME_PER_SECOND + frames+=minutes*SECOND_PER_MINUTE*FRAME_PER_SECOND + frames+=hours*MINUTE_PER_HOUR*SECOND_PER_MINUTE*FRAME_PER_SECOND + return int(frames) + +def ms_to_strh(ms): + negative = ms < 0 + if negative: + ms = -ms + millisecond = ms % MS_PER_SECOND + seconds = (ms - millisecond) / MS_PER_SECOND + minute_seconds = seconds % SECOND_PER_MINUTE + minutes = (seconds - minute_seconds) / SECOND_PER_MINUTE + hour_minutes = minutes % MINUTE_PER_HOUR + hours = (minutes - hour_minutes) / MINUTE_PER_HOUR + + return format_strh(negative, hours, hour_minutes, minute_seconds, millisecond) + +def strh_to_ms(strh): + # 0123456789abc + # hh:mm:ss.mss + hours = int(strh[0:2]) + minutes = int(strh[3:5]) + seconds = int(strh[6:8]) + ms = int(strh[9:]) + + ms+=seconds*MS_PER_SECOND + ms+=minutes*SECOND_PER_MINUTE*MS_PER_SECOND + ms+=hours*MINUTE_PER_HOUR*SECOND_PER_MINUTE*MS_PER_SECOND + return int(ms) + +def format_strh(negative, hours, minutes, seconds, ms): + negative_string = "-" if negative else "" + second_string = f"{int(seconds)}" + if seconds < 10: + second_string = "0" + second_string + + minute_string = f"{int(minutes)}" + if minutes < 10: + minute_string = "0" + minute_string + + hour_string = f"{int(hours)}:" + if hours < 10: + hour_string = "0" + hour_string + + if ms < 10: + ms_string = f".00{int(ms)}" + elif ms < 100: + ms_string = f".0{int(ms)}" + else: + ms_string = f".{int(ms)}" + + return f"{negative_string}{hour_string}{minute_string}:{second_string}{ms_string}" +MODE_CONVERT = 0 +MODE_ADD = 1 +MODE_SUBTRACT = 2 + +def run(): + parser = argparse.ArgumentParser(description='Process some times.') + parser.add_argument('-a', action='store_true', help="Add the arguments") + parser.add_argument('-s', action='store_true', help="Subtract the arguments") + parser.add_argument('-c', action='store_true', help="Convert the arguments (default)") + parser.add_argument('-f', action='store_true', help="Output frames (30 fps)") + parser.add_argument('-t', action='store_true', help="Output time code") + parser.add_argument('-m', action='store_true', help="Millisecond mode. Input numbers are treated as ms and will not align to 30 fps") + + parser.add_argument('times', metavar='T', type=str, nargs='+', help='time input, can be frames or time code (hh:mm:ss.mss)') + + args = parser.parse_args() + mode = MODE_CONVERT + if args.c: + mode = MODE_CONVERT + elif args.a: + mode = MODE_ADD + elif args.s: + mode = MODE_SUBTRACT + + ms_mode = args.m + + storage = [] + for t in args.times: + if is_strh(t): + if ms_mode: + current = strh_to_ms(t) + else: + current = strh_to_frm(t) + elif is_frame(t): + current = int(t) + else: + print(f"Error: not recognized: {t}") + sys.exit(1) + if len(storage) == 0 or mode == MODE_CONVERT: + storage.append(current) + elif mode == MODE_ADD: + storage[0] = storage[0] + current + elif mode == MODE_SUBTRACT: + storage[0] = storage[0] - current + + if args.t: + for s in storage: + if ms_mode: + print(ms_to_strh(s)) + else: + print(frm_to_strh(s)) + else: + for s in storage: + print(s) + + +if __name__ == "__main__": + run() + diff --git a/packages/item-animated/test.html b/packages/item-animated/test.html new file mode 100644 index 0000000..0788316 --- /dev/null +++ b/packages/item-animated/test.html @@ -0,0 +1,83 @@ + + + + + + + +
+
+ + + diff --git a/packages/item-assets/.gitignore b/packages/item-assets/.gitignore new file mode 100644 index 0000000..aa2ee90 --- /dev/null +++ b/packages/item-assets/.gitignore @@ -0,0 +1,4 @@ +/data +/icons +*.webp +*.png diff --git a/packages/item-assets/Cargo.toml b/packages/item-assets/Cargo.toml new file mode 100644 index 0000000..901c3f4 --- /dev/null +++ b/packages/item-assets/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "skybook-item-sprites-generator" +version = "0.0.0" +publish = false +edition = "2021" + +[dependencies] +anyhow = "1.0.94" +codize = "0.3.3" +image = "0.25.5" +serde = { version = "1.0.216", features = ["derive"] } +serde_json = "1.0.134" +thiserror = "2.0.9" +webp = "0.3.0" + + +[[bin]] +name = "skybook-item-sprites-generator" +path = "generator/main.rs" diff --git a/packages/item-assets/Taskfile.yml b/packages/item-assets/Taskfile.yml new file mode 100644 index 0000000..6bb3a3d --- /dev/null +++ b/packages/item-assets/Taskfile.yml @@ -0,0 +1,31 @@ +version: '3' + +tasks: + pull-priv: + desc: Pull private assets for building the package. Requires gcloud access + cmds: + - rm -rf icons src/images/*.png + - gcloud storage cp -r gs://ist-private/icons . + - gcloud storage cp -r gs://ist-private/images src + + + build: + desc: Build the sprite sheets + cmds: + - rm -rf src/special src/sprites + - cargo run --release + - cp -R icons/SP/Item src/special + + pull: + desc: Pull the assets for development + cmds: + - cmd: echo "this command is not yet available" + silent: true + + push: + desc: Push the generated assets. Requires gcloud access + cmds: + - gcloud storage cp src/sprites/*.webp gs://ist-private/sprites + + + diff --git a/packages/item-assets/generator/canvas.rs b/packages/item-assets/generator/canvas.rs new file mode 100644 index 0000000..9d10409 --- /dev/null +++ b/packages/item-assets/generator/canvas.rs @@ -0,0 +1,82 @@ +use std::path::PathBuf; + +use anyhow::{anyhow, bail}; +use image::imageops::{self, FilterType}; +use image::DynamicImage; +use webp::Encoder; + +use crate::error::Error; + +#[derive(Debug, Clone)] +pub struct Canvas { + /// The output path of the sprite sheet + pub output: PathBuf, + /// Number of sprite on each side of the canvas + /// + /// Total number is this squared + pub sprite_per_side: u32, + /// Padding around each sprite + pub padding: u32, + /// Resolution to scale each sprite to + pub scale_to: u32, + + /// The encoding quality + pub quality: f32, + + image: DynamicImage +} + +impl Canvas { + pub fn new(output: PathBuf, sprite_per_side: u32, outer_resolution: u32, inner_resolution: u32, quality: f32) -> Self { + let padding2 = outer_resolution - inner_resolution; + if padding2 % 2 != 0 { + panic!("padding must be even"); + } + let padding = padding2 / 2; + + let canvas_size = sprite_per_side * outer_resolution; + let image = DynamicImage::new_rgba8(canvas_size, canvas_size); + + Self { + output, + sprite_per_side, + padding, + scale_to: inner_resolution, + quality, + image + } + } + + pub fn load_image(&mut self, position: usize, image: &DynamicImage) -> anyhow::Result<()>{ + if position >= self.sprite_per_side as usize * self.sprite_per_side as usize { + bail!("position out of bounds"); + } + let resized = + DynamicImage::ImageRgba8(imageops::resize(image, self.scale_to, self.scale_to, FilterType::Lanczos3)); + let outer_res = self.scale_to + self.padding * 2; + let y = (position / self.sprite_per_side as usize) * (outer_res as usize); + let y = y as u32 + self.padding; + let x = (position % self.sprite_per_side as usize) * (outer_res as usize); + let x = x as u32 + self.padding; + imageops::overlay(&mut self.image, &resized, x as i64, y as i64); + + Ok(()) + } + +/// Encode a webp image and write it to a file +/// +/// Return the file size +pub fn write(&self) -> anyhow::Result { + let encoder = match Encoder::from_image(&self.image) { + Ok(e) => e, + Err(e) => Err(anyhow!("Could not create encoder: {}", e))?, + }; + + let memory = encoder.encode_simple(false, self.quality).map_err(Error::from)?; + let len = memory.len(); + + std::fs::write(&self.output, &*memory)?; + + Ok(len) +} +} diff --git a/packages/item-assets/generator/error.rs b/packages/item-assets/generator/error.rs new file mode 100644 index 0000000..90b54a8 --- /dev/null +++ b/packages/item-assets/generator/error.rs @@ -0,0 +1,26 @@ +use std::sync::PoisonError; + +use webp::WebPEncodingError; + + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("lock is poisoned: {0}")] + Poison(String), + #[error("image is not square: {0}, width={1}, height={2}")] + NotSquare(String, u32, u32), + #[error("could not encode image: {0}")] + WebpEncode(String), +} + +impl From> for Error { + fn from(e: PoisonError) -> Self { + Error::Poison(format!("{}", e)) + } +} + +impl From for Error { + fn from(e: WebPEncodingError) -> Self { + Error::WebpEncode(format!("{:?}", e)) + } +} diff --git a/packages/item-assets/generator/main.rs b/packages/item-assets/generator/main.rs new file mode 100644 index 0000000..e73dd57 --- /dev/null +++ b/packages/item-assets/generator/main.rs @@ -0,0 +1,253 @@ +// use clap::Parser; + +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, bail}; +use canvas::Canvas; +use codize::{cblock, cconcat, clist}; + +mod error; +use error::Error; + +mod sprite_sheet; +use sprite_sheet::{Metadata, SpriteSheet}; + +mod canvas; + +fn main() { + if let Err(e) = generate() { + eprintln!("error: {:?}", e); + } +} + +fn generate() -> anyhow::Result<()> { + let home = find_home()?; + let icons_dir = home.join("icons"); + if !icons_dir.exists() { + bail!("icons directory does not exist: {}", icons_dir.display()); + } + + let sprites_dir = home.join("src").join("sprites"); + if !sprites_dir.exists() { + std::fs::create_dir_all(&sprites_dir)?; + } + println!("configuring actor chunks..."); + + let mut chunks = vec![ + // chunk 0 + find_images(&icons_dir, &["CapturedActor", "Item", "PlayerItem"])?, + // chunk 1 + find_images( + &icons_dir, + &[ + "Bullet", + "WeaponBow", + "WeaponLargeSword", + "WeaponShield", + "WeaponSmallSword", + "WeaponSpear", + ], + )?, + // chunk 2 + find_images( + &icons_dir, + &[ + "ArmorHead", + "ArmorLower", + "ArmorUpper", + "HorseReins", + "HorseSaddle", + "CookResult", + ], + )?, + ]; + + let special_dir = icons_dir.join("SP"); + + // add the fallback "dummy" image + let dummy_path = special_dir.join("Dummy.png"); + if !dummy_path.exists() { + bail!("Dummy image does not exist: {}", dummy_path.display()); + } + println!("adding dummy image to last chunk"); + chunks.last_mut().unwrap().push(dummy_path); + + // print stat + for (i, chunk) in chunks.iter().enumerate() { + println!("chunk {}: {} images", i, chunk.len()); + } + println!("loading actor sprites..."); + + // load the individual icons into sprite sheets + let mut sprite_sheets = (0..chunks.len()) + .map(|i| { + let mut sprite_sheet = SpriteSheet::new(i as u16); + let lo_res_path = sprites_dir.join(format!("chunk{}x32.webp", i)); + let lo_res = Canvas::new(lo_res_path, 16, 32, 28, 75f32); + let hi_res_path = sprites_dir.join(format!("chunk{}x64.webp", i)); + let hi_res = Canvas::new(hi_res_path, 16, 64, 56, 90f32); + sprite_sheet.add_canvas(lo_res); + sprite_sheet.add_canvas(hi_res); + sprite_sheet + }) + .collect::>(); + + for (sheet, chunk) in sprite_sheets.iter_mut().zip(chunks) { + for file in chunk { + let name = file.file_stem().unwrap().to_string_lossy().into_owned(); + sheet.add_sprite(&name, file)?; + } + } + + + println!("encoding actor sprite sheets..."); + for (i, sheet) in sprite_sheets.iter().enumerate() { + println!("-- chunk {}", i); + let sizes = sheet.write()?; + println!(" low resolution: {} bytes", sizes[0]); + println!(" high resolution: {} bytes", sizes[1]); + } + + println!("writing actor metadata..."); + let mut metadata = Metadata::default(); + for sheet in &sprite_sheets { + sheet.add_metadata(&mut metadata)?; + } + let ts_chunk_type = (0..sprite_sheets.len()) + .map(|i| i.to_string()) + .collect::>() + .join("|"); + let metadata = serde_json::to_string(&metadata)?; + let metadata_ts = cconcat![ + // imports + cconcat!((0..sprite_sheets.len()) + .map(|i| { format!("import chunk{i}x32 from \"./chunk{i}x32.webp?url\";") })), + cconcat!((0..sprite_sheets.len()) + .map(|i| { format!("import chunk{i}x64 from \"./chunk{i}x64.webp?url\";") })), + + // chunkmap classnames + cblock! { + "export const ActorChunkClasses = {", + [ + clist!("" => (0..sprite_sheets.len()).map(|i| { + format!("\".sprite-chunk{i}x32\": {{ backgroundImage: `url(${{chunk{i}x32}})` }},") + })), + clist!("" => (0..sprite_sheets.len()).map(|i| { + format!("\".sprite-chunk{i}x64\": {{ backgroundImage: `url(${{chunk{i}x64}})` }},") + })), + clist!("" => (0..sprite_sheets.len()).map(|i| { + format!("\".sprite-mask-chunk{i}x32\": {{ maskImage: `url(${{chunk{i}x32}})` }},") + })), + clist!("" => (0..sprite_sheets.len()).map(|i| { + format!("\".sprite-mask-chunk{i}x64\": {{ maskImage: `url(${{chunk{i}x64}})` }},") + })), + ], + "} as const;" + }, + + // metadata for finding where an actor is + "/** Actor => [Chunk, Position]*/", + format!( + "export type ActorMetadata = Record;", + ts_chunk_type + ), + format!( + "export const ActorMetadata: ActorMetadata = JSON.parse(`{}`)", + metadata + ), + ]; + + std::fs::write(sprites_dir.join("ActorMetadata.gen.ts"), metadata_ts.to_string())?; + + println!("configuring modifier chunks..."); + let modifier_chunk = find_images(&icons_dir, &["SpecialStatus"])?; + let mut modifier_sheet = SpriteSheet::new(0); + let modifier_path = sprites_dir.join("modifiers.webp"); + let modifier_canvas = Canvas::new(modifier_path, 8, 48, 48, 90f32); + modifier_sheet.add_canvas(modifier_canvas); + + println!("loading modifier sprites..."); + for file in modifier_chunk { + let name = file.file_stem().unwrap().to_string_lossy().into_owned(); + modifier_sheet.add_sprite(&name, file)?; + } + + println!("encoding modifier sprite sheet..."); + let sizes = modifier_sheet.write()?; + println!(" modifiers: {} bytes", sizes[0]); + + println!("writing modifier metadata..."); + let mut metadata = Metadata::default(); + modifier_sheet.add_metadata(&mut metadata)?; + let metadata = serde_json::to_string(&metadata)?; + let metadata_ts = cconcat![ + // imports + "import modifiers from \"./modifiers.webp?url\";", + + // chunkmap classnames + cblock! { + "export const ModifierChunkClasses = {", + [ + "\".sprite-modifiers\": { backgroundImage: `url(${modifiers})` },", + ], + "} as const;" + }, + + "/** Modifier => [Chunk, Position]*/", + "export type ModifierMetadata = Record;", + format!( + "export const ModifierMetadata: ModifierMetadata = JSON.parse(`{}`)", + metadata + ), + ]; + + std::fs::write(sprites_dir.join("ModifierMetadata.gen.ts"), metadata_ts.to_string())?; + + println!("done!"); + + Ok(()) +} + +fn find_images(data_dir: &Path, profiles: &[&str]) -> anyhow::Result> { + // we need to synchronously list all images to guarantee + // consistent ordering in the output + let mut out = Vec::new(); + for profile in profiles { + let profile_dir = data_dir.join(profile); + if !profile_dir.exists() { + bail!( + "Profile directory does not exist: {}", + profile_dir.display() + ); + } + + let mut images = Vec::new(); + for entry in profile_dir.read_dir()? { + let entry = entry?; + let path = entry.path(); + if !path.is_file() { + bail!("Not a file: {}", path.display()); + } + images.push(path); + } + println!("profile: {} ({} actors)", profile, images.len()); + images.sort(); + out.extend(images); + } + Ok(out) +} + +/// Find the item-assets package directory +/// if running from cargo +fn find_home() -> anyhow::Result { + let e = std::env::current_exe()?; + let root_path = e + .parent() // /target/release + .and_then(|x| x.parent()) // /target + .and_then(|x| x.parent()) // / + .ok_or_else(|| anyhow!("Could not find parent of exe"))?; + let mut path = root_path.to_path_buf(); + path.push("packages"); + path.push("item-assets"); + Ok(path) +} diff --git a/packages/item-assets/generator/sprite_sheet.rs b/packages/item-assets/generator/sprite_sheet.rs new file mode 100644 index 0000000..f935f0e --- /dev/null +++ b/packages/item-assets/generator/sprite_sheet.rs @@ -0,0 +1,103 @@ +use std::collections::BTreeMap; +use std::path::Path; + +use anyhow::{bail, Context}; +use image::GenericImageView; +use serde::{Deserialize, Serialize}; + +use crate::canvas::Canvas; +use crate::Error; + +#[derive(Debug, Clone)] +pub struct SpriteSheet { + /// The chunk number + pub chunk: u16, + /// The name of the sprites + pub sprites: Vec, + /// The canvases for the sprite sheet, each canvas is a different resolution/ config + pub canvases: Vec, +} + +impl SpriteSheet { + pub fn new(chunk: u16) -> Self { + Self { + chunk, + sprites: Vec::new(), + canvases: Vec::new(), + } + } + + /// Add a canvas configuration for output + pub fn add_canvas(&mut self, canvas: Canvas) { + self.canvases.push(canvas); + } + + + /// Add the metadata of the sprite sheet to the metadata object + /// + /// Returns how many sprites were added + pub fn add_metadata(&self, metadata: &mut Metadata) -> anyhow::Result { + for (pos, name) in self.sprites.iter().enumerate() { + metadata.register(name, self.chunk, pos)?; + } + Ok(self.sprites.len()) + } + + /// Load an image from a file and encode it into the sprite sheet + pub fn add_sprite(&mut self, name: &str, path: impl AsRef) -> anyhow::Result<()> { + let position = { + let position = self.sprites.len(); + self.sprites.push(name.to_string()); + position + }; + self.load_image(path, position)?; + Ok(()) + } + /// Load an image file into sprite sheet canvas + fn load_image( + &mut self, + path: impl AsRef, + position: usize, + ) -> anyhow::Result<()> { + let path = path.as_ref(); + let image = image::open(&path).context(format!("Could not open image: {}", path.display()))?; + let (w, h) = image.dimensions(); + if w != h { + Err(Error::NotSquare(path.display().to_string(), w, h))?; + } + for canvas in &mut self.canvases { + canvas.load_image(position, &image)?; + } + + Ok(()) + } + + /// Write the sprite sheets to output files + /// + /// Returns the sizes of the canvases + pub fn write(&self) -> anyhow::Result> { + let mut sizes = Vec::with_capacity(self.canvases.len()); + for canvas in &self.canvases { + sizes.push(canvas.write()?); + } + Ok(sizes) + } +} + +/// The data of a sprite sheet +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[repr(transparent)] +#[serde(transparent)] +pub struct Metadata(BTreeMap); +impl Metadata { + pub fn register(&mut self, name: &str, chunk: u16, position: usize) -> anyhow::Result<()> { + if self + .0 + .insert(name.to_string(), (chunk, position.try_into()?)) + .is_some() + { + bail!("Sprite {name} registered more than once"); + } + Ok(()) + } +} diff --git a/packages/item-assets/package.json b/packages/item-assets/package.json new file mode 100644 index 0000000..e20887d --- /dev/null +++ b/packages/item-assets/package.json @@ -0,0 +1,16 @@ +{ + "name": "skybook-item-assets", + "private": true, + "version": "0.0.0", + "files": [ + "src/**/*" + ], + "exports": { + ".": "./src/index.ts" + }, + "peerDependencies": { + "@griffel/react": "*", + "@types/react": "*", + "react": "*" + } +} diff --git a/packages/item-assets/src/ActorRemap.gen.ts b/packages/item-assets/src/ActorRemap.gen.ts new file mode 100644 index 0000000..dde8535 --- /dev/null +++ b/packages/item-assets/src/ActorRemap.gen.ts @@ -0,0 +1,10 @@ + +/** + * This file is generated by resolve-icon-actor.py + * DO NOT EDIT MANUALLY + */ + +/** Actor name -> icon actor name, if different */ +export type ActorRemap = Record; + +export const ActorRemap: ActorRemap = JSON.parse(`{"Armor_086_Upper":"Armor_014_Upper","Armor_084_Upper":"Armor_014_Upper","Armor_085_Upper":"Armor_014_Upper","Armor_083_Upper":"Armor_014_Upper","Armor_234_Head":"Armor_230_Head","Armor_231_Head":"Armor_230_Head","Armor_233_Head":"Armor_230_Head","Armor_232_Head":"Armor_230_Head","Armor_229_Head":"Armor_225_Head","Armor_228_Head":"Armor_225_Head","Armor_227_Head":"Armor_225_Head","Armor_226_Head":"Armor_225_Head","Armor_097_Lower":"Armor_020_Lower","Armor_096_Lower":"Armor_020_Lower","Armor_095_Lower":"Armor_020_Lower","Armor_098_Lower":"Armor_020_Lower","Armor_214_Lower":"Armor_210_Lower","Armor_213_Lower":"Armor_210_Lower","Armor_211_Lower":"Armor_210_Lower","Armor_212_Lower":"Armor_210_Lower","Armor_226_Upper":"Armor_225_Upper","Armor_228_Upper":"Armor_225_Upper","Armor_227_Upper":"Armor_225_Upper","Armor_229_Upper":"Armor_225_Upper","Armor_204_Lower":"Armor_200_Lower","Armor_203_Lower":"Armor_200_Lower","Armor_201_Lower":"Armor_200_Lower","Armor_202_Lower":"Armor_200_Lower","Armor_208_Upper":"Armor_205_Upper","Armor_207_Upper":"Armor_205_Upper","Armor_206_Upper":"Armor_205_Upper","Armor_209_Upper":"Armor_205_Upper","Armor_217_Lower":"Armor_215_Lower","Armor_219_Lower":"Armor_215_Lower","Armor_216_Lower":"Armor_215_Lower","Armor_218_Lower":"Armor_215_Lower","Armor_004_Head":"Armor_001_Head","Armor_002_Head":"Armor_001_Head","Armor_003_Head":"Armor_001_Head","Armor_015_Head":"Armor_001_Head","Armor_036_Upper":"Armor_009_Upper","Armor_073_Upper":"Armor_009_Upper","Armor_072_Upper":"Armor_009_Upper","Armor_071_Upper":"Armor_009_Upper","Armor_132_Head":"Obj_Head_027","Armor_129_Head":"Obj_Head_027","Armor_027_Head":"Obj_Head_027","Armor_131_Head":"Obj_Head_027","Armor_130_Head":"Obj_Head_027","Armor_187_Head":"Armor_181_Head","Armor_188_Head":"Armor_181_Head","Armor_189_Head":"Armor_181_Head","Armor_186_Head":"Armor_181_Head","Armor_063_Lower":"Armor_006_Lower","Armor_064_Lower":"Armor_006_Lower","Armor_007_Lower":"Armor_006_Lower","Armor_062_Lower":"Armor_006_Lower","Armor_100_Upper":"Armor_021_Upper","Armor_102_Upper":"Armor_021_Upper","Armor_099_Upper":"Armor_021_Upper","Armor_101_Upper":"Armor_021_Upper","Armor_117_Head":"Obj_Head_024","Armor_119_Head":"Obj_Head_024","Armor_120_Head":"Obj_Head_024","Armor_024_Head":"Obj_Head_024","Armor_118_Head":"Obj_Head_024","Armor_063_Upper":"Armor_006_Upper","Armor_064_Upper":"Armor_006_Upper","Armor_062_Upper":"Armor_006_Upper","Armor_007_Upper":"Armor_006_Upper","Armor_084_Head":"Armor_014_Head","Armor_083_Head":"Armor_014_Head","Armor_086_Head":"Armor_014_Head","Armor_085_Head":"Armor_014_Head","Armor_214_Upper":"Armor_210_Upper","Armor_211_Upper":"Armor_210_Upper","Armor_213_Upper":"Armor_210_Upper","Armor_212_Upper":"Armor_210_Upper","Armor_036_Lower":"Armor_009_Lower","Armor_073_Lower":"Armor_009_Lower","Armor_072_Lower":"Armor_009_Lower","Armor_071_Lower":"Armor_009_Lower","Armor_111_Upper":"Armor_048_Upper","Armor_114_Upper":"Armor_048_Upper","Armor_113_Upper":"Armor_048_Upper","Armor_112_Upper":"Armor_048_Upper","Armor_100_Head":"Armor_021_Head","Armor_101_Head":"Armor_021_Head","Armor_099_Head":"Armor_021_Head","Armor_102_Head":"Armor_021_Head","Armor_156_Lower":"Armor_141_Lower","Armor_157_Lower":"Armor_141_Lower","Armor_140_Lower":"Armor_141_Lower","Armor_158_Lower":"Armor_141_Lower","Armor_159_Lower":"Armor_141_Lower","Armor_062_Head":"Armor_006_Head","Armor_063_Head":"Armor_006_Head","Armor_007_Head":"Armor_006_Head","Armor_064_Head":"Armor_006_Head","Armor_096_Upper":"Armor_020_Upper","Armor_098_Upper":"Armor_020_Upper","Armor_097_Upper":"Armor_020_Upper","Armor_095_Upper":"Armor_020_Upper","Weapon_Sword_072":"Weapon_Sword_070","Weapon_Sword_071":"Weapon_Sword_070","Weapon_Sword_081":"Weapon_Sword_070","Weapon_Sword_080":"Weapon_Sword_070","Armor_037_Upper":"Armor_011_Upper","Armor_075_Upper":"Armor_011_Upper","Armor_074_Upper":"Armor_011_Upper","Armor_076_Upper":"Armor_011_Upper","Armor_106_Lower":"Armor_046_Lower","Armor_105_Lower":"Armor_046_Lower","Armor_104_Lower":"Armor_046_Lower","Armor_103_Lower":"Armor_046_Lower","Armor_060_Head":"Armor_005_Head","Armor_039_Head":"Armor_005_Head","Armor_061_Head":"Armor_005_Head","Armor_035_Head":"Armor_005_Head","Armor_096_Head":"Armor_020_Head","Armor_097_Head":"Armor_020_Head","Armor_095_Head":"Armor_020_Head","Armor_098_Head":"Armor_020_Head","Armor_077_Lower":"Armor_012_Lower","Armor_042_Lower":"Armor_012_Lower","Armor_079_Lower":"Armor_012_Lower","Armor_078_Lower":"Armor_012_Lower","Armor_168_Head":"Armor_184_Head","Armor_198_Head":"Armor_184_Head","Armor_199_Head":"Armor_184_Head","Armor_169_Head":"Armor_184_Head","Armor_106_Upper":"Armor_046_Upper","Armor_103_Upper":"Armor_046_Upper","Armor_104_Upper":"Armor_046_Upper","Armor_105_Upper":"Armor_046_Upper","Armor_039_Upper":"Armor_005_Upper","Armor_061_Upper":"Armor_005_Upper","Armor_035_Upper":"Armor_005_Upper","Armor_060_Upper":"Armor_005_Upper","Armor_087_Lower":"Armor_017_Lower","Armor_090_Lower":"Armor_017_Lower","Armor_088_Lower":"Armor_017_Lower","Armor_089_Lower":"Armor_017_Lower","Armor_066_Lower":"Armor_008_Lower","Armor_040_Lower":"Armor_008_Lower","Armor_067_Lower":"Armor_008_Lower","Armor_065_Lower":"Armor_008_Lower","Armor_083_Lower":"Armor_014_Lower","Armor_085_Lower":"Armor_014_Lower","Armor_084_Lower":"Armor_014_Lower","Armor_086_Lower":"Armor_014_Lower","Armor_112_Lower":"Armor_048_Lower","Armor_113_Lower":"Armor_048_Lower","Armor_114_Lower":"Armor_048_Lower","Armor_111_Lower":"Armor_048_Lower","Armor_231_Upper":"Armor_230_Upper","Armor_233_Upper":"Armor_230_Upper","Armor_234_Upper":"Armor_230_Upper","Armor_232_Upper":"Armor_230_Upper","Armor_202_Upper":"Armor_200_Upper","Armor_201_Upper":"Armor_200_Upper","Armor_203_Upper":"Armor_200_Upper","Armor_204_Upper":"Armor_200_Upper","Armor_040_Upper":"Armor_008_Upper","Armor_065_Upper":"Armor_008_Upper","Armor_066_Upper":"Armor_008_Upper","Armor_067_Upper":"Armor_008_Upper","Armor_137_Head":"Obj_Head_029","Armor_140_Head":"Obj_Head_029","Armor_029_Head":"Obj_Head_029","Armor_139_Head":"Obj_Head_029","Armor_138_Head":"Obj_Head_029","Armor_211_Head":"Armor_210_Head","Armor_212_Head":"Armor_210_Head","Armor_213_Head":"Armor_210_Head","Armor_214_Head":"Armor_210_Head","Armor_123_Head":"Obj_Head_025","Armor_122_Head":"Obj_Head_025","Armor_124_Head":"Obj_Head_025","Armor_121_Head":"Obj_Head_025","Armor_025_Head":"Obj_Head_025","Armor_153_Lower":"Armor_049_Lower","Armor_152_Lower":"Armor_049_Lower","Armor_155_Lower":"Armor_049_Lower","Armor_154_Lower":"Armor_049_Lower","Armor_002_Lower":"Armor_001_Lower","Armor_015_Lower":"Armor_001_Lower","Armor_003_Lower":"Armor_001_Lower","Armor_004_Lower":"Armor_001_Lower","Armor_077_Upper":"Armor_012_Upper","Armor_079_Upper":"Armor_012_Upper","Armor_078_Upper":"Armor_012_Upper","Armor_042_Upper":"Armor_012_Upper","Armor_088_Upper":"Armor_017_Upper","Armor_089_Upper":"Armor_017_Upper","Armor_087_Upper":"Armor_017_Upper","Armor_090_Upper":"Armor_017_Upper","Armor_075_Head":"Armor_011_Head","Armor_037_Head":"Armor_011_Head","Armor_074_Head":"Armor_011_Head","Armor_076_Head":"Armor_011_Head","Armor_100_Lower":"Armor_021_Lower","Armor_101_Lower":"Armor_021_Lower","Armor_099_Lower":"Armor_021_Lower","Armor_102_Lower":"Armor_021_Lower","Armor_223_Head":"Armor_220_Head","Armor_222_Head":"Armor_220_Head","Armor_221_Head":"Armor_220_Head","Armor_224_Head":"Armor_220_Head","Armor_193_Head":"Armor_182_Head","Armor_192_Head":"Armor_182_Head","Armor_191_Head":"Armor_182_Head","Armor_190_Head":"Armor_182_Head","Armor_229_Lower":"Armor_225_Lower","Armor_227_Lower":"Armor_225_Lower","Armor_226_Lower":"Armor_225_Lower","Armor_228_Lower":"Armor_225_Lower","Armor_072_Head":"Armor_009_Head","Armor_071_Head":"Armor_009_Head","Armor_073_Head":"Armor_009_Head","Armor_036_Head":"Armor_009_Head","Armor_231_Lower":"Armor_230_Lower","Armor_233_Lower":"Armor_230_Lower","Armor_234_Lower":"Armor_230_Lower","Armor_232_Lower":"Armor_230_Lower","Armor_015_Upper":"Armor_001_Upper","Armor_004_Upper":"Armor_001_Upper","Armor_002_Upper":"Armor_001_Upper","Armor_003_Upper":"Armor_001_Upper","Armor_077_Head":"Armor_012_Head","Armor_078_Head":"Armor_012_Head","Armor_079_Head":"Armor_012_Head","Armor_042_Head":"Armor_012_Head","Armor_065_Head":"Armor_008_Head","Armor_067_Head":"Armor_008_Head","Armor_066_Head":"Armor_008_Head","Armor_040_Head":"Armor_008_Head","Armor_134_Head":"Obj_Head_028","Armor_136_Head":"Obj_Head_028","Armor_028_Head":"Obj_Head_028","Armor_135_Head":"Obj_Head_028","Armor_133_Head":"Obj_Head_028","Armor_039_Lower":"Armor_005_Lower","Armor_035_Lower":"Armor_005_Lower","Armor_061_Lower":"Armor_005_Lower","Armor_060_Lower":"Armor_005_Lower","Armor_219_Head":"Armor_215_Head","Armor_217_Head":"Armor_215_Head","Armor_216_Head":"Armor_215_Head","Armor_218_Head":"Armor_215_Head","Armor_089_Head":"Armor_017_Head","Armor_090_Head":"Armor_017_Head","Armor_088_Head":"Armor_017_Head","Armor_087_Head":"Armor_017_Head","Armor_074_Lower":"Armor_011_Lower","Armor_075_Lower":"Armor_011_Lower","Armor_037_Lower":"Armor_011_Lower","Armor_076_Lower":"Armor_011_Lower","Armor_194_Head":"Armor_183_Head","Armor_196_Head":"Armor_183_Head","Armor_197_Head":"Armor_183_Head","Armor_195_Head":"Armor_183_Head","Armor_125_Head":"Obj_Head_026","Armor_026_Head":"Obj_Head_026","Armor_126_Head":"Obj_Head_026","Armor_128_Head":"Obj_Head_026","Armor_127_Head":"Obj_Head_026","Armor_113_Head":"Armor_048_Head","Armor_114_Head":"Armor_048_Head","Armor_111_Head":"Armor_048_Head","Armor_112_Head":"Armor_048_Head","Armor_103_Head":"Armor_046_Head","Armor_106_Head":"Armor_046_Head","Armor_104_Head":"Armor_046_Head","Armor_105_Head":"Armor_046_Head","Obj_SheikPadLv2":"Obj_DRStone_Get","Armor_148_Upper":"Armor_116_Upper","Armor_149_Upper":"Armor_116_Upper","Armor_151_Upper":"Armor_116_Upper","Armor_150_Upper":"Armor_116_Upper","Armor_206_Lower":"Armor_205_Lower","Armor_207_Lower":"Armor_205_Lower","Armor_208_Lower":"Armor_205_Lower","Armor_209_Lower":"Armor_205_Lower","Armor_208_Head":"Armor_205_Head","Armor_206_Head":"Armor_205_Head","Armor_209_Head":"Armor_205_Head","Armor_207_Head":"Armor_205_Head","Armor_218_Upper":"Armor_215_Upper","Armor_219_Upper":"Armor_215_Upper","Armor_216_Upper":"Armor_215_Upper","Armor_217_Upper":"Armor_215_Upper","Armor_202_Head":"Armor_200_Head","Armor_203_Head":"Armor_200_Head","Armor_204_Head":"Armor_200_Head","Armor_201_Head":"Armor_200_Head"}`); diff --git a/packages/item-assets/src/ActorSprite.tsx b/packages/item-assets/src/ActorSprite.tsx new file mode 100644 index 0000000..40ebca3 --- /dev/null +++ b/packages/item-assets/src/ActorSprite.tsx @@ -0,0 +1,281 @@ +import { memo } from "react"; +import { makeStaticStyles, makeStyles, mergeClasses } from "@griffel/react"; + +import { ActorChunkClasses, ActorMetadata } from "./sprites/ActorMetadata.gen.ts"; +import { ActorRemap } from "./ActorRemap.gen.ts"; + +export type ActorSpriteProps = { + /** Name of the Actor to display */ + actor: string; + + /** + * Name of the Cook effect if any (as in msyt translation files) + * + * This is to display the correct icon for elixirs. + * Ignored if Actor is not "Item_Cook_C_17" + */ + effect?: string; + + /** + * Use the low resolution/quality version of images. Also + * disables animations + */ + cheap?: boolean; + + /** + * Disable all animations even if `cheap` is false + */ + disableAnimation?: boolean; + + /** + * Use styles to indicate that this slot is supposed to + * not have an icon in the game (like multiple animated slots) + */ + blank?: boolean; + + /** + * Display the red effect for badly damaged + * + * The implementation only shows for non-animated images, which + * is true for all weapons + */ + badlyDamaged?: boolean; + + /** + * Use the deactivated state of certain actors + * - Master Sword (any): The state where the sword is recharging + * - One-hit Obliterator (502): The state where weapon is recharging + * - Champion Abilities: disabled state + */ + deactive?: boolean; + + /** + * Use the "powered up" state for Master Sword + */ + powered?: boolean; +}; + +const useChunkClasses = makeStaticStyles(ActorChunkClasses); + +const useStyles = makeStyles({ + sprite: { + backgroundRepeat: "no-repeat", + width: "64px", + height: "64px", + display: "block", + }, + cheap: { + backgroundSize: "1024px", // for some reason 200% doesn't work + }, + spriteSoulImage: { + position: "relative", + }, + animatedSimple: { + backgroundSize: "64px", + }, + soulOffset: { + top: "-11.4px", + }, + soulOffsetDLC: { + top: "-19px", + left: "0px", + }, + blank: { + filter: "grayscale(100%)", + opacity: 0.8, + }, + deactiveMasterSword: { + opacity: 0.5, + }, + damageContainer:{ + overflow: "hidden", + }, + damage: { + width: "1024px", + height: "1024px", + backgroundColor: "rgba(255, 0, 0, 0.6)", + }, + damageCheap: { + transformOrigin: "top left", + scale: 2, + width: "512px", + height: "512px", + backgroundColor: "rgba(255, 0, 0, 0.6)", + }, + damageAnimation: { + animationIterationCount: "infinite", + animationDuration: "1s", + animationName: { + "0%": { + opacity: 1, + }, + "25%": { + opacity: 0.9, + }, + "50%": { + opacity: 0.7, + }, + "75%": { + opacity: 0.4, + }, + "100%": { + opacity: 0, + }, + } + } +}); + +const SpriteImpl: React.FC = ({ actor, effect, cheap, disableAnimation, deactive, powered, blank, badlyDamaged}) => { + useChunkClasses(); + const styles = useStyles(); + + let baseClass = mergeClasses(styles.sprite, blank && styles.blank); + + disableAnimation = disableAnimation || cheap; + + // Handle simple animated images - Travel Medallion, 5 orbs + // if not animated, it's in the sprite sheet + if (!disableAnimation) { + if (/Obj_(WarpDLC|DungeonClearSeal|HeroSeal_(Gerudo|Goron|Rito|Zora))/.test(actor)) { + return ( +
+ ); + } + } + + const iconActor = mapActor(actor, !!deactive, !!powered, effect); + if (iconActor === "Weapon_Sword_070_Disabled") { + baseClass = mergeClasses(baseClass, styles.deactiveMasterSword); + } + + // Special handling for Champion Abilities: + // - Active ones are larger and needs to be offseted + // - Deactive ones has animation + if (isChampionAbility(iconActor)) { + const dlc = iconActor.includes("DLC"); + // active - either animated or not, with offset + if (!deactive) { + const ext = disableAnimation ? "png" : "webp"; + return ( +
+ + +
+ ); + } + // inactive - if animated, use different sprite + if (!disableAnimation) { + return ( +
+ ); + } + } + + const [chunk, position] = ActorMetadata[iconActor]; + const backgroundPosition = getBackgroundPosition(position); + + const chunkClass = `chunk${chunk}x${cheap ? "32" : "64"}` + + return ( +
+ { + badlyDamaged && ( +
+ ) + } +
+ ); +}; + +export const ActorSprite = memo(SpriteImpl); + +/** + * Remap an actor to its icon actor name + */ +const mapActor = ( + actor: string, + deactive: boolean, + powered: boolean, + effect: string | undefined +): string => { + // cannot manually pass in a "Disabled" actor + if (actor.endsWith("_Disabled")) { + return "Dummy"; + } + // Remap actor name to icon actor name + if (actor in ActorRemap) { + actor = ActorRemap[actor]; + } + + // Master Sword + if (actor === "Weapon_Sword_070") { + if (deactive) { + return "Weapon_Sword_070_Disabled"; + } + if (powered) { + return "Weapon_Sword_072"; + } + } + + // regular OHO, use powered up icon unless deactivated + if (!deactive && actor === "Weapon_Sword_502") { + actor = "Weapon_Sword_503"; + } + + // Champion Abilities + if (isChampionAbility(actor)) { + // need to return here because animated images are not + // in Dummy + if (deactive) { + return `${actor}_Disabled`; + } + return actor; + } + + // Elixirs - they are the same actor, but icon + // depends on the effect + if (effect && actor === "Item_Cook_C_17") { + actor = `${actor}_${effect}`; + } + + if (!(actor in ActorMetadata)) { + return "Dummy"; + } + return actor; +}; + + +const getBackgroundPosition = (position: number) => { + const NUM = 16; + const SIZE = 64; + const x = position % NUM; + const y = Math.floor(position / NUM); + return `-${x * SIZE}px -${y * SIZE}px`; +} + +const isChampionAbility = (actor: string) => { + return /^Obj_(DLC_)?HeroSoul_(Gerudo|Goron|Rito|Zora)(_Disabled)?$/.test(actor); +} diff --git a/packages/item-assets/src/ModifierSprite.tsx b/packages/item-assets/src/ModifierSprite.tsx new file mode 100644 index 0000000..b86038c --- /dev/null +++ b/packages/item-assets/src/ModifierSprite.tsx @@ -0,0 +1,51 @@ +import { makeStaticStyles, makeStyles, mergeClasses } from "@griffel/react"; +import { memo } from "react"; + +import { ModifierChunkClasses, ModifierMetadata } from "./sprites/ModifierMetadata.gen.ts"; + +export type ModifierSpriteProps = { + /** Name of the special status to show */ + status: string; +} + +const useChunkClasses = makeStaticStyles(ModifierChunkClasses); + +const useStyles = makeStyles({ + sprite: { + backgroundRepeat: "no-repeat", + backgroundSize: "160px 160px", // 20px * 8 + width: "20px", + height: "20px", + display: "block", + } +}); + +const SpriteImpl: React.FC = ({ status }) => { + useChunkClasses(); + const styles = useStyles(); + if (!ModifierMetadata[status]) { + return null; + } + const [_, position] = ModifierMetadata[status]; + const backgroundPosition = getBackgroundPosition(position); + + + return ( +
+
+ ); +}; + +export const ModifierSprite = memo(SpriteImpl); + +const getBackgroundPosition = (position: number) => { + const NUM = 8; + const SIZE = 20; + const x = position % NUM; + const y = Math.floor(position / NUM); + return `-${x * SIZE}px -${y * SIZE}px`; +} diff --git a/packages/item-assets/src/images/index.ts b/packages/item-assets/src/images/index.ts new file mode 100644 index 0000000..dc6af88 --- /dev/null +++ b/packages/item-assets/src/images/index.ts @@ -0,0 +1,10 @@ +import { makeStyles } from "@griffel/react"; +import sheikahBg from "./SheikahBackground.png?url"; + +/** Get the styles for using static assets */ +export const useStaticAssetStyles = makeStyles({ + /** Use the sheikah background image */ + sheikahBg: { + backgroundImage: `url(${sheikahBg})`, + } +}); diff --git a/packages/item-assets/src/index.ts b/packages/item-assets/src/index.ts new file mode 100644 index 0000000..a034100 --- /dev/null +++ b/packages/item-assets/src/index.ts @@ -0,0 +1,5 @@ +export * from "./images/index.ts"; +export * from "./sprites/ActorMetadata.gen.ts"; +export * from "./sprites/ModifierMetadata.gen.ts"; +export * from "./ActorSprite.tsx"; +export * from "./ModifierSprite.tsx"; diff --git a/packages/item-assets/src/sprites/ActorMetadata.gen.ts b/packages/item-assets/src/sprites/ActorMetadata.gen.ts new file mode 100644 index 0000000..dffed1e --- /dev/null +++ b/packages/item-assets/src/sprites/ActorMetadata.gen.ts @@ -0,0 +1,23 @@ +import chunk0x32 from "./chunk0x32.webp?url"; +import chunk1x32 from "./chunk1x32.webp?url"; +import chunk2x32 from "./chunk2x32.webp?url"; +import chunk0x64 from "./chunk0x64.webp?url"; +import chunk1x64 from "./chunk1x64.webp?url"; +import chunk2x64 from "./chunk2x64.webp?url"; +export const ActorChunkClasses = { + ".sprite-chunk0x32": { backgroundImage: `url(${chunk0x32})` }, + ".sprite-chunk1x32": { backgroundImage: `url(${chunk1x32})` }, + ".sprite-chunk2x32": { backgroundImage: `url(${chunk2x32})` }, + ".sprite-chunk0x64": { backgroundImage: `url(${chunk0x64})` }, + ".sprite-chunk1x64": { backgroundImage: `url(${chunk1x64})` }, + ".sprite-chunk2x64": { backgroundImage: `url(${chunk2x64})` }, + ".sprite-mask-chunk0x32": { maskImage: `url(${chunk0x32})` }, + ".sprite-mask-chunk1x32": { maskImage: `url(${chunk1x32})` }, + ".sprite-mask-chunk2x32": { maskImage: `url(${chunk2x32})` }, + ".sprite-mask-chunk0x64": { maskImage: `url(${chunk0x64})` }, + ".sprite-mask-chunk1x64": { maskImage: `url(${chunk1x64})` }, + ".sprite-mask-chunk2x64": { maskImage: `url(${chunk2x64})` }, +} as const; +/** Actor => [Chunk, Position]*/ +export type ActorMetadata = Record; +export const ActorMetadata: ActorMetadata = JSON.parse(`{"AncientArrow":[1,0],"Animal_Insect_A":[0,0],"Animal_Insect_AA":[0,1],"Animal_Insect_AB":[0,2],"Animal_Insect_B":[0,3],"Animal_Insect_C":[0,4],"Animal_Insect_E":[0,5],"Animal_Insect_F":[0,6],"Animal_Insect_G":[0,7],"Animal_Insect_H":[0,8],"Animal_Insect_I":[0,9],"Animal_Insect_M":[0,10],"Animal_Insect_N":[0,11],"Animal_Insect_P":[0,12],"Animal_Insect_Q":[0,13],"Animal_Insect_R":[0,14],"Animal_Insect_S":[0,15],"Animal_Insect_T":[0,16],"Animal_Insect_X":[0,17],"Armor_001_Head":[2,0],"Armor_001_Lower":[2,47],"Armor_001_Upper":[2,76],"Armor_005_Head":[2,1],"Armor_005_Lower":[2,48],"Armor_005_Upper":[2,77],"Armor_006_Head":[2,2],"Armor_006_Lower":[2,49],"Armor_006_Upper":[2,78],"Armor_008_Head":[2,3],"Armor_008_Lower":[2,50],"Armor_008_Upper":[2,79],"Armor_009_Head":[2,4],"Armor_009_Lower":[2,51],"Armor_009_Upper":[2,80],"Armor_011_Head":[2,5],"Armor_011_Lower":[2,52],"Armor_011_Upper":[2,81],"Armor_012_Head":[2,6],"Armor_012_Lower":[2,53],"Armor_012_Upper":[2,82],"Armor_014_Head":[2,7],"Armor_014_Lower":[2,54],"Armor_014_Upper":[2,83],"Armor_017_Head":[2,8],"Armor_017_Lower":[2,55],"Armor_017_Upper":[2,84],"Armor_020_Head":[2,9],"Armor_020_Lower":[2,56],"Armor_020_Upper":[2,85],"Armor_021_Head":[2,10],"Armor_021_Lower":[2,57],"Armor_021_Upper":[2,86],"Armor_022_Head":[2,11],"Armor_043_Lower":[2,58],"Armor_043_Upper":[2,87],"Armor_044_Upper":[2,88],"Armor_045_Head":[2,12],"Armor_046_Head":[2,13],"Armor_046_Lower":[2,59],"Armor_046_Upper":[2,89],"Armor_048_Head":[2,14],"Armor_048_Lower":[2,60],"Armor_048_Upper":[2,90],"Armor_049_Lower":[2,61],"Armor_053_Head":[2,15],"Armor_053_Lower":[2,62],"Armor_053_Upper":[2,91],"Armor_055_Head":[2,16],"Armor_056_Head":[2,17],"Armor_115_Head":[2,18],"Armor_116_Upper":[2,92],"Armor_141_Lower":[2,63],"Armor_160_Head":[2,19],"Armor_160_Lower":[2,64],"Armor_160_Upper":[2,93],"Armor_170_Upper":[2,94],"Armor_171_Head":[2,20],"Armor_171_Lower":[2,65],"Armor_171_Upper":[2,95],"Armor_172_Head":[2,21],"Armor_173_Head":[2,22],"Armor_174_Head":[2,23],"Armor_174_Lower":[2,66],"Armor_174_Upper":[2,96],"Armor_175_Upper":[2,97],"Armor_176_Head":[2,24],"Armor_177_Head":[2,25],"Armor_178_Head":[2,26],"Armor_179_Head":[2,27],"Armor_179_Lower":[2,67],"Armor_179_Upper":[2,98],"Armor_180_Head":[2,28],"Armor_180_Lower":[2,68],"Armor_180_Upper":[2,99],"Armor_181_Head":[2,29],"Armor_182_Head":[2,30],"Armor_183_Head":[2,31],"Armor_184_Head":[2,32],"Armor_185_Head":[2,33],"Armor_185_Lower":[2,69],"Armor_185_Upper":[2,100],"Armor_200_Head":[2,34],"Armor_200_Lower":[2,70],"Armor_200_Upper":[2,101],"Armor_205_Head":[2,35],"Armor_205_Lower":[2,71],"Armor_205_Upper":[2,102],"Armor_210_Head":[2,36],"Armor_210_Lower":[2,72],"Armor_210_Upper":[2,103],"Armor_215_Head":[2,37],"Armor_215_Lower":[2,73],"Armor_215_Upper":[2,104],"Armor_220_Head":[2,38],"Armor_225_Head":[2,39],"Armor_225_Lower":[2,74],"Armor_225_Upper":[2,105],"Armor_230_Head":[2,40],"Armor_230_Lower":[2,75],"Armor_230_Upper":[2,106],"BeeHome":[0,18],"BombArrow_A":[1,1],"BrightArrow":[1,2],"BrightArrowTP":[1,3],"Dummy":[2,248],"ElectricArrow":[1,4],"FireArrow":[1,5],"GameRomHorseReins_01":[2,107],"GameRomHorseReins_02":[2,108],"GameRomHorseReins_03":[2,109],"GameRomHorseReins_04":[2,110],"GameRomHorseReins_05":[2,111],"GameRomHorseReins_10":[2,112],"GameRomHorseSaddle_01":[2,113],"GameRomHorseSaddle_02":[2,114],"GameRomHorseSaddle_03":[2,115],"GameRomHorseSaddle_04":[2,116],"GameRomHorseSaddle_05":[2,117],"GameRomHorseSaddle_10":[2,118],"Get_TwnObj_DLC_MemorialPicture_A_01":[0,19],"IceArrow":[1,6],"Item_Boiled_01":[0,20],"Item_ChilledFish_01":[0,21],"Item_ChilledFish_02":[0,22],"Item_ChilledFish_03":[0,23],"Item_ChilledFish_04":[0,24],"Item_ChilledFish_05":[0,25],"Item_ChilledFish_06":[0,26],"Item_ChilledFish_07":[0,27],"Item_ChilledFish_08":[0,28],"Item_ChilledFish_09":[0,29],"Item_Chilled_01":[0,30],"Item_Chilled_02":[0,31],"Item_Chilled_03":[0,32],"Item_Chilled_04":[0,33],"Item_Chilled_05":[0,34],"Item_Chilled_06":[0,35],"Item_Cook_A_01":[2,119],"Item_Cook_A_02":[2,120],"Item_Cook_A_03":[2,121],"Item_Cook_A_04":[2,122],"Item_Cook_A_05":[2,123],"Item_Cook_A_07":[2,124],"Item_Cook_A_08":[2,125],"Item_Cook_A_09":[2,126],"Item_Cook_A_10":[2,127],"Item_Cook_A_11":[2,128],"Item_Cook_A_12":[2,129],"Item_Cook_A_13":[2,130],"Item_Cook_A_14":[2,131],"Item_Cook_B_01":[2,132],"Item_Cook_B_02":[2,133],"Item_Cook_B_05":[2,134],"Item_Cook_B_06":[2,135],"Item_Cook_B_11":[2,136],"Item_Cook_B_12":[2,137],"Item_Cook_B_13":[2,138],"Item_Cook_B_15":[2,139],"Item_Cook_B_16":[2,140],"Item_Cook_B_17":[2,141],"Item_Cook_B_18":[2,142],"Item_Cook_B_19":[2,143],"Item_Cook_B_20":[2,144],"Item_Cook_B_21":[2,145],"Item_Cook_B_22":[2,146],"Item_Cook_B_23":[2,147],"Item_Cook_C_16":[2,148],"Item_Cook_C_17":[2,149],"Item_Cook_C_17_AllSpeed":[2,150],"Item_Cook_C_17_AttackUp":[2,151],"Item_Cook_C_17_DefenseUp":[2,152],"Item_Cook_C_17_ExGutsMaxUp":[2,153],"Item_Cook_C_17_Fireproof":[2,154],"Item_Cook_C_17_GutsRecover":[2,155],"Item_Cook_C_17_LifeMaxUp":[2,156],"Item_Cook_C_17_Quietness":[2,157],"Item_Cook_C_17_ResistCold":[2,158],"Item_Cook_C_17_ResistElectric":[2,159],"Item_Cook_C_17_ResistHot":[2,160],"Item_Cook_D_01":[2,161],"Item_Cook_D_02":[2,162],"Item_Cook_D_03":[2,163],"Item_Cook_D_04":[2,164],"Item_Cook_D_05":[2,165],"Item_Cook_D_06":[2,166],"Item_Cook_D_07":[2,167],"Item_Cook_D_08":[2,168],"Item_Cook_D_09":[2,169],"Item_Cook_D_10":[2,170],"Item_Cook_E_01":[2,171],"Item_Cook_E_02":[2,172],"Item_Cook_E_03":[2,173],"Item_Cook_E_04":[2,174],"Item_Cook_F_01":[2,175],"Item_Cook_F_02":[2,176],"Item_Cook_F_03":[2,177],"Item_Cook_F_04":[2,178],"Item_Cook_G_02":[2,179],"Item_Cook_G_03":[2,180],"Item_Cook_G_04":[2,181],"Item_Cook_G_05":[2,182],"Item_Cook_G_06":[2,183],"Item_Cook_G_09":[2,184],"Item_Cook_G_10":[2,185],"Item_Cook_G_11":[2,186],"Item_Cook_G_12":[2,187],"Item_Cook_G_13":[2,188],"Item_Cook_G_14":[2,189],"Item_Cook_G_15":[2,190],"Item_Cook_G_16":[2,191],"Item_Cook_G_17":[2,192],"Item_Cook_H_01":[2,193],"Item_Cook_H_02":[2,194],"Item_Cook_H_03":[2,195],"Item_Cook_I_01":[2,196],"Item_Cook_I_02":[2,197],"Item_Cook_I_03":[2,198],"Item_Cook_I_04":[2,199],"Item_Cook_I_05":[2,200],"Item_Cook_I_06":[2,201],"Item_Cook_I_07":[2,202],"Item_Cook_I_08":[2,203],"Item_Cook_I_09":[2,204],"Item_Cook_I_10":[2,205],"Item_Cook_I_11":[2,206],"Item_Cook_I_12":[2,207],"Item_Cook_I_13":[2,208],"Item_Cook_I_14":[2,209],"Item_Cook_I_15":[2,210],"Item_Cook_I_16":[2,211],"Item_Cook_I_17":[2,212],"Item_Cook_J_01":[2,213],"Item_Cook_J_02":[2,214],"Item_Cook_J_03":[2,215],"Item_Cook_J_04":[2,216],"Item_Cook_J_05":[2,217],"Item_Cook_J_06":[2,218],"Item_Cook_J_07":[2,219],"Item_Cook_J_08":[2,220],"Item_Cook_J_09":[2,221],"Item_Cook_K_01":[2,222],"Item_Cook_K_02":[2,223],"Item_Cook_K_03":[2,224],"Item_Cook_K_04":[2,225],"Item_Cook_K_05":[2,226],"Item_Cook_K_06":[2,227],"Item_Cook_K_07":[2,228],"Item_Cook_K_08":[2,229],"Item_Cook_K_09":[2,230],"Item_Cook_L_01":[2,231],"Item_Cook_L_02":[2,232],"Item_Cook_L_03":[2,233],"Item_Cook_L_04":[2,234],"Item_Cook_L_05":[2,235],"Item_Cook_M_01":[2,236],"Item_Cook_N_01":[2,237],"Item_Cook_N_02":[2,238],"Item_Cook_N_03":[2,239],"Item_Cook_N_04":[2,240],"Item_Cook_O_01":[2,241],"Item_Cook_O_02":[2,242],"Item_Cook_P_01":[2,243],"Item_Cook_P_02":[2,244],"Item_Cook_P_03":[2,245],"Item_Cook_P_04":[2,246],"Item_Cook_P_05":[2,247],"Item_Enemy_00":[0,36],"Item_Enemy_01":[0,37],"Item_Enemy_02":[0,38],"Item_Enemy_03":[0,39],"Item_Enemy_04":[0,40],"Item_Enemy_05":[0,41],"Item_Enemy_06":[0,42],"Item_Enemy_07":[0,43],"Item_Enemy_08":[0,44],"Item_Enemy_12":[0,45],"Item_Enemy_13":[0,46],"Item_Enemy_14":[0,47],"Item_Enemy_15":[0,48],"Item_Enemy_16":[0,49],"Item_Enemy_17":[0,50],"Item_Enemy_18":[0,51],"Item_Enemy_19":[0,52],"Item_Enemy_20":[0,53],"Item_Enemy_21":[0,54],"Item_Enemy_24":[0,55],"Item_Enemy_25":[0,56],"Item_Enemy_26":[0,57],"Item_Enemy_27":[0,58],"Item_Enemy_28":[0,59],"Item_Enemy_29":[0,60],"Item_Enemy_30":[0,61],"Item_Enemy_31":[0,62],"Item_Enemy_32":[0,63],"Item_Enemy_33":[0,64],"Item_Enemy_34":[0,65],"Item_Enemy_38":[0,66],"Item_Enemy_39":[0,67],"Item_Enemy_40":[0,68],"Item_Enemy_41":[0,69],"Item_Enemy_42":[0,70],"Item_Enemy_43":[0,71],"Item_Enemy_44":[0,72],"Item_Enemy_45":[0,73],"Item_Enemy_46":[0,74],"Item_Enemy_47":[0,75],"Item_Enemy_48":[0,76],"Item_Enemy_49":[0,77],"Item_Enemy_50":[0,78],"Item_Enemy_51":[0,79],"Item_Enemy_52":[0,80],"Item_Enemy_53":[0,81],"Item_Enemy_54":[0,82],"Item_Enemy_55":[0,83],"Item_Enemy_56":[0,84],"Item_Enemy_57":[0,85],"Item_FishGet_A":[0,86],"Item_FishGet_B":[0,87],"Item_FishGet_C":[0,88],"Item_FishGet_D":[0,89],"Item_FishGet_E":[0,90],"Item_FishGet_F":[0,91],"Item_FishGet_G":[0,92],"Item_FishGet_H":[0,93],"Item_FishGet_I":[0,94],"Item_FishGet_J":[0,95],"Item_FishGet_K":[0,96],"Item_FishGet_L":[0,97],"Item_FishGet_M":[0,98],"Item_FishGet_X":[0,99],"Item_FishGet_Z":[0,100],"Item_Fruit_A":[0,101],"Item_Fruit_B":[0,102],"Item_Fruit_C":[0,103],"Item_Fruit_D":[0,104],"Item_Fruit_E":[0,105],"Item_Fruit_F":[0,106],"Item_Fruit_G":[0,107],"Item_Fruit_H":[0,108],"Item_Fruit_I":[0,109],"Item_Fruit_J":[0,110],"Item_Fruit_K":[0,111],"Item_Fruit_L":[0,112],"Item_InsectGet_K":[0,113],"Item_InsectGet_O":[0,114],"Item_InsectGet_Z":[0,115],"Item_Material_01":[0,116],"Item_Material_02":[0,117],"Item_Material_03":[0,118],"Item_Material_04":[0,119],"Item_Material_05":[0,120],"Item_Material_06":[0,121],"Item_Material_07":[0,122],"Item_Material_08":[0,123],"Item_Meat_01":[0,124],"Item_Meat_02":[0,125],"Item_Meat_06":[0,126],"Item_Meat_07":[0,127],"Item_Meat_11":[0,128],"Item_Meat_12":[0,129],"Item_MushroomGet_D":[0,130],"Item_Mushroom_A":[0,131],"Item_Mushroom_B":[0,132],"Item_Mushroom_C":[0,133],"Item_Mushroom_E":[0,134],"Item_Mushroom_F":[0,135],"Item_Mushroom_H":[0,136],"Item_Mushroom_J":[0,137],"Item_Mushroom_L":[0,138],"Item_Mushroom_M":[0,139],"Item_Mushroom_N":[0,140],"Item_Mushroom_O":[0,141],"Item_Ore_A":[0,142],"Item_Ore_B":[0,143],"Item_Ore_C":[0,144],"Item_Ore_D":[0,145],"Item_Ore_E":[0,146],"Item_Ore_F":[0,147],"Item_Ore_G":[0,148],"Item_Ore_H":[0,149],"Item_Ore_I":[0,150],"Item_Ore_J":[0,151],"Item_PlantGet_A":[0,152],"Item_PlantGet_B":[0,153],"Item_PlantGet_C":[0,154],"Item_PlantGet_E":[0,155],"Item_PlantGet_F":[0,156],"Item_PlantGet_G":[0,157],"Item_PlantGet_H":[0,158],"Item_PlantGet_I":[0,159],"Item_PlantGet_J":[0,160],"Item_PlantGet_L":[0,161],"Item_PlantGet_M":[0,162],"Item_PlantGet_O":[0,163],"Item_PlantGet_Q":[0,164],"Item_RoastFish_01":[0,165],"Item_RoastFish_02":[0,166],"Item_RoastFish_03":[0,167],"Item_RoastFish_04":[0,168],"Item_RoastFish_07":[0,169],"Item_RoastFish_09":[0,170],"Item_RoastFish_11":[0,171],"Item_RoastFish_13":[0,172],"Item_RoastFish_15":[0,173],"Item_Roast_01":[0,174],"Item_Roast_02":[0,175],"Item_Roast_03":[0,176],"Item_Roast_04":[0,177],"Item_Roast_05":[0,178],"Item_Roast_06":[0,179],"Item_Roast_07":[0,180],"Item_Roast_08":[0,181],"Item_Roast_09":[0,182],"Item_Roast_10":[0,183],"Item_Roast_11":[0,184],"Item_Roast_12":[0,185],"Item_Roast_13":[0,186],"Item_Roast_15":[0,187],"Item_Roast_16":[0,188],"Item_Roast_18":[0,189],"Item_Roast_19":[0,190],"Item_Roast_24":[0,191],"Item_Roast_27":[0,192],"Item_Roast_28":[0,193],"Item_Roast_31":[0,194],"Item_Roast_32":[0,195],"Item_Roast_33":[0,196],"Item_Roast_36":[0,197],"Item_Roast_37":[0,198],"Item_Roast_38":[0,199],"Item_Roast_39":[0,200],"Item_Roast_40":[0,201],"Item_Roast_41":[0,202],"Item_Roast_45":[0,203],"Item_Roast_46":[0,204],"Item_Roast_48":[0,205],"Item_Roast_49":[0,206],"Item_Roast_50":[0,207],"Item_Roast_51":[0,208],"Item_Roast_52":[0,209],"Item_Roast_53":[0,210],"NormalArrow":[1,7],"Obj_Armor_115_Head":[0,211],"Obj_DLC_HeroSeal_Gerudo":[0,212],"Obj_DLC_HeroSeal_Goron":[0,213],"Obj_DLC_HeroSeal_Rito":[0,214],"Obj_DLC_HeroSeal_Zora":[0,215],"Obj_DLC_HeroSoul_Gerudo_Disabled":[0,216],"Obj_DLC_HeroSoul_Goron_Disabled":[0,217],"Obj_DLC_HeroSoul_Rito_Disabled":[0,218],"Obj_DLC_HeroSoul_Zora_Disabled":[0,219],"Obj_DRStone_Get":[0,231],"Obj_DungeonClearSeal":[0,220],"Obj_FireWoodBundle":[0,221],"Obj_Head_024":[2,41],"Obj_Head_025":[2,42],"Obj_Head_026":[2,43],"Obj_Head_027":[2,44],"Obj_Head_028":[2,45],"Obj_Head_029":[2,46],"Obj_HeroSoul_Gerudo_Disabled":[0,222],"Obj_HeroSoul_Goron_Disabled":[0,223],"Obj_HeroSoul_Rito_Disabled":[0,224],"Obj_HeroSoul_Zora_Disabled":[0,225],"Obj_KorokNuts":[0,226],"Obj_Maracas":[0,227],"Obj_ProofBook":[0,228],"Obj_ProofKorok":[0,229],"Obj_WarpDLC":[0,230],"PlayerStole2":[0,232],"Weapon_Bow_001":[1,8],"Weapon_Bow_002":[1,9],"Weapon_Bow_003":[1,10],"Weapon_Bow_004":[1,11],"Weapon_Bow_006":[1,12],"Weapon_Bow_009":[1,13],"Weapon_Bow_011":[1,14],"Weapon_Bow_013":[1,15],"Weapon_Bow_014":[1,16],"Weapon_Bow_015":[1,17],"Weapon_Bow_016":[1,18],"Weapon_Bow_017":[1,19],"Weapon_Bow_023":[1,20],"Weapon_Bow_026":[1,21],"Weapon_Bow_027":[1,22],"Weapon_Bow_028":[1,23],"Weapon_Bow_029":[1,24],"Weapon_Bow_030":[1,25],"Weapon_Bow_032":[1,26],"Weapon_Bow_033":[1,27],"Weapon_Bow_035":[1,28],"Weapon_Bow_036":[1,29],"Weapon_Bow_038":[1,30],"Weapon_Bow_040":[1,31],"Weapon_Bow_071":[1,32],"Weapon_Bow_072":[1,33],"Weapon_Lsword_001":[1,34],"Weapon_Lsword_002":[1,35],"Weapon_Lsword_003":[1,36],"Weapon_Lsword_004":[1,37],"Weapon_Lsword_005":[1,38],"Weapon_Lsword_006":[1,39],"Weapon_Lsword_010":[1,40],"Weapon_Lsword_011":[1,41],"Weapon_Lsword_012":[1,42],"Weapon_Lsword_013":[1,43],"Weapon_Lsword_014":[1,44],"Weapon_Lsword_015":[1,45],"Weapon_Lsword_016":[1,46],"Weapon_Lsword_017":[1,47],"Weapon_Lsword_018":[1,48],"Weapon_Lsword_019":[1,49],"Weapon_Lsword_020":[1,50],"Weapon_Lsword_023":[1,51],"Weapon_Lsword_024":[1,52],"Weapon_Lsword_027":[1,53],"Weapon_Lsword_029":[1,54],"Weapon_Lsword_030":[1,55],"Weapon_Lsword_031":[1,56],"Weapon_Lsword_032":[1,57],"Weapon_Lsword_033":[1,58],"Weapon_Lsword_034":[1,59],"Weapon_Lsword_035":[1,60],"Weapon_Lsword_036":[1,61],"Weapon_Lsword_037":[1,62],"Weapon_Lsword_038":[1,63],"Weapon_Lsword_041":[1,64],"Weapon_Lsword_045":[1,65],"Weapon_Lsword_047":[1,66],"Weapon_Lsword_051":[1,67],"Weapon_Lsword_054":[1,68],"Weapon_Lsword_055":[1,69],"Weapon_Lsword_056":[1,70],"Weapon_Lsword_057":[1,71],"Weapon_Lsword_059":[1,72],"Weapon_Lsword_060":[1,73],"Weapon_Lsword_074":[1,74],"Weapon_Shield_001":[1,75],"Weapon_Shield_002":[1,76],"Weapon_Shield_003":[1,77],"Weapon_Shield_004":[1,78],"Weapon_Shield_005":[1,79],"Weapon_Shield_006":[1,80],"Weapon_Shield_007":[1,81],"Weapon_Shield_008":[1,82],"Weapon_Shield_009":[1,83],"Weapon_Shield_013":[1,84],"Weapon_Shield_014":[1,85],"Weapon_Shield_015":[1,86],"Weapon_Shield_016":[1,87],"Weapon_Shield_017":[1,88],"Weapon_Shield_018":[1,89],"Weapon_Shield_021":[1,90],"Weapon_Shield_022":[1,91],"Weapon_Shield_023":[1,92],"Weapon_Shield_025":[1,93],"Weapon_Shield_026":[1,94],"Weapon_Shield_030":[1,95],"Weapon_Shield_031":[1,96],"Weapon_Shield_032":[1,97],"Weapon_Shield_033":[1,98],"Weapon_Shield_034":[1,99],"Weapon_Shield_035":[1,100],"Weapon_Shield_036":[1,101],"Weapon_Shield_037":[1,102],"Weapon_Shield_038":[1,103],"Weapon_Shield_040":[1,104],"Weapon_Shield_041":[1,105],"Weapon_Shield_042":[1,106],"Weapon_Shield_057":[1,107],"Weapon_Spear_001":[1,160],"Weapon_Spear_002":[1,161],"Weapon_Spear_003":[1,162],"Weapon_Spear_004":[1,163],"Weapon_Spear_005":[1,164],"Weapon_Spear_006":[1,165],"Weapon_Spear_007":[1,166],"Weapon_Spear_008":[1,167],"Weapon_Spear_009":[1,168],"Weapon_Spear_010":[1,169],"Weapon_Spear_011":[1,170],"Weapon_Spear_012":[1,171],"Weapon_Spear_013":[1,172],"Weapon_Spear_014":[1,173],"Weapon_Spear_015":[1,174],"Weapon_Spear_016":[1,175],"Weapon_Spear_017":[1,176],"Weapon_Spear_018":[1,177],"Weapon_Spear_021":[1,178],"Weapon_Spear_022":[1,179],"Weapon_Spear_023":[1,180],"Weapon_Spear_024":[1,181],"Weapon_Spear_025":[1,182],"Weapon_Spear_027":[1,183],"Weapon_Spear_028":[1,184],"Weapon_Spear_029":[1,185],"Weapon_Spear_030":[1,186],"Weapon_Spear_031":[1,187],"Weapon_Spear_032":[1,188],"Weapon_Spear_033":[1,189],"Weapon_Spear_034":[1,190],"Weapon_Spear_035":[1,191],"Weapon_Spear_036":[1,192],"Weapon_Spear_037":[1,193],"Weapon_Spear_038":[1,194],"Weapon_Spear_047":[1,195],"Weapon_Spear_049":[1,196],"Weapon_Spear_050":[1,197],"Weapon_Sword_001":[1,108],"Weapon_Sword_002":[1,109],"Weapon_Sword_003":[1,110],"Weapon_Sword_004":[1,111],"Weapon_Sword_005":[1,112],"Weapon_Sword_006":[1,113],"Weapon_Sword_007":[1,114],"Weapon_Sword_008":[1,115],"Weapon_Sword_009":[1,116],"Weapon_Sword_013":[1,117],"Weapon_Sword_014":[1,118],"Weapon_Sword_015":[1,119],"Weapon_Sword_016":[1,120],"Weapon_Sword_017":[1,121],"Weapon_Sword_018":[1,122],"Weapon_Sword_019":[1,123],"Weapon_Sword_020":[1,124],"Weapon_Sword_021":[1,125],"Weapon_Sword_022":[1,126],"Weapon_Sword_023":[1,127],"Weapon_Sword_024":[1,128],"Weapon_Sword_025":[1,129],"Weapon_Sword_027":[1,130],"Weapon_Sword_029":[1,131],"Weapon_Sword_030":[1,132],"Weapon_Sword_031":[1,133],"Weapon_Sword_033":[1,134],"Weapon_Sword_034":[1,135],"Weapon_Sword_035":[1,136],"Weapon_Sword_040":[1,137],"Weapon_Sword_041":[1,138],"Weapon_Sword_043":[1,139],"Weapon_Sword_044":[1,140],"Weapon_Sword_047":[1,141],"Weapon_Sword_048":[1,142],"Weapon_Sword_049":[1,143],"Weapon_Sword_050":[1,144],"Weapon_Sword_051":[1,145],"Weapon_Sword_052":[1,146],"Weapon_Sword_053":[1,147],"Weapon_Sword_057":[1,148],"Weapon_Sword_058":[1,149],"Weapon_Sword_059":[1,150],"Weapon_Sword_060":[1,151],"Weapon_Sword_061":[1,152],"Weapon_Sword_062":[1,153],"Weapon_Sword_070":[1,154],"Weapon_Sword_070_Disabled":[1,155],"Weapon_Sword_072":[1,156],"Weapon_Sword_073":[1,157],"Weapon_Sword_502":[1,158],"Weapon_Sword_503":[1,159]}`) \ No newline at end of file diff --git a/packages/item-assets/src/sprites/ModifierMetadata.gen.ts b/packages/item-assets/src/sprites/ModifierMetadata.gen.ts new file mode 100644 index 0000000..572627c --- /dev/null +++ b/packages/item-assets/src/sprites/ModifierMetadata.gen.ts @@ -0,0 +1,7 @@ +import modifiers from "./modifiers.webp?url"; +export const ModifierChunkClasses = { + ".sprite-modifiers": { backgroundImage: `url(${modifiers})` }, +} as const; +/** Modifier => [Chunk, Position]*/ +export type ModifierMetadata = Record; +export const ModifierMetadata: ModifierMetadata = JSON.parse(`{"AddGuard":[0,0],"AddGuardPlus":[0,1],"AddLife":[0,2],"AddLifePlus":[0,3],"AddPower":[0,4],"AddPowerPlus":[0,5],"AddPowerPlus_Bow":[0,6],"AddPower_Bow":[0,7],"AllSpeed":[0,8],"AttackUp":[0,9],"ClimbSpeedUp":[0,10],"Critical":[0,11],"DefenseUp":[0,12],"ExGutsMaxUp":[0,13],"Fireproof":[0,14],"GutsRecover":[0,15],"LifeMaxUp":[0,16],"LifeRecover":[0,17],"LongThrow":[0,18],"Quietness":[0,19],"RapidFire":[0,20],"ReduceAncientEnemyDamge":[0,21],"ResistCold":[0,22],"ResistElectric":[0,23],"ResistFreeze":[0,24],"ResistHot":[0,25],"ResistLightning":[0,26],"SandMoveSpeedUp":[0,27],"SnowMovingSpeed":[0,28],"SpreadFire_3":[0,29],"SpreadFire_5":[0,30],"SpreadFire_X":[0,31],"SurfMaster":[0,32],"SurfMaster_White":[0,33],"SwimSpeedUp":[0,34],"Zoom":[0,35],"Zoom_White":[0,36]}`) \ No newline at end of file diff --git a/packages/item-assets/tsconfig.json b/packages/item-assets/tsconfig.json new file mode 100644 index 0000000..1f7887e --- /dev/null +++ b/packages/item-assets/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../config/tsconfig-vite-app.json", + "include": ["src"], +} diff --git a/packages/item-system/.gitignore b/packages/item-system/.gitignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/packages/item-system/.gitignore @@ -0,0 +1 @@ +/node_modules diff --git a/app/index.html b/packages/item-system/index.html similarity index 57% rename from app/index.html rename to packages/item-system/index.html index e4b78ea..ebdc13e 100644 --- a/app/index.html +++ b/packages/item-system/index.html @@ -2,12 +2,11 @@ - - Vite + React + TS + Item Slots Test
- + diff --git a/packages/item-system/package.json b/packages/item-system/package.json new file mode 100644 index 0000000..5f39276 --- /dev/null +++ b/packages/item-system/package.json @@ -0,0 +1,23 @@ +{ + "name": "skybook-item-system", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@fluentui/react-components": "*", + "@fluentui/react-icons": "*", + "react": "*", + "react-dom": "*", + "skybook-item-assets": "*", + "skybook-localization": "*" + }, + "exports": { + ".": "./src/index.ts" + } +} diff --git a/legacy/public/assets/font/Calamity-Regular.otf b/packages/item-system/src/Calamity-Regular.otf similarity index 100% rename from legacy/public/assets/font/Calamity-Regular.otf rename to packages/item-system/src/Calamity-Regular.otf diff --git a/packages/item-system/src/CalamitySans.css b/packages/item-system/src/CalamitySans.css new file mode 100644 index 0000000..a5d8e18 --- /dev/null +++ b/packages/item-system/src/CalamitySans.css @@ -0,0 +1,5 @@ +@font-face { + font-family: CalamitySans; + src: url("./Calamity-Regular.otf") format("opentype"); +} + diff --git a/packages/item-system/src/ItemSlot.tsx b/packages/item-system/src/ItemSlot.tsx new file mode 100644 index 0000000..60fe722 --- /dev/null +++ b/packages/item-system/src/ItemSlot.tsx @@ -0,0 +1,304 @@ +import "./CalamitySans.css"; +import { makeStyles, mergeClasses } from "@griffel/react"; +import { Text } from "@fluentui/react-components"; + +import { ActorSprite, ActorSpriteProps, ModifierSprite } from "skybook-item-assets"; + +import { type ItemSlotInfo } from "./data/ItemSlotInfo.ts"; +import { Link24Regular, Link32Regular } from "@fluentui/react-icons"; +import { CookEffect, PouchItemType, SpecialStatus } from "./data/enums.ts"; +import { getModifierInfo } from "./data/ModifierInfo.ts"; +import { getActorParam } from "./data/ActorData.ts"; + +const useStyles = makeStyles({ + container: { + position: "relative", + width: "72px", + height: "72px", + "& *": { + pointerEvents: "none", + } + }, + broken: { + backgroundColor: "#660000", + }, + // main item slot box + boxOutline: { + position: "absolute", + width: "64px", + height: "64px", + top: "4px", + left: "4px", + }, + boxOutlineColor: { + backgroundColor: "#333333bb", + }, + // the darker inside + lighter border + boxInside: { + position: "absolute", + boxSizing: "border-box", + width: "62px", + height: "62px", + top: "5px", + left: "5px", + }, + boxInsideBorder: { + border: "1px solid #999999", + }, + boxInsideHighlightBorder: { + border: "1px solid #ffee00", + }, + boxInsideColor: { + backgroundColor: "#000000cc", + }, + equipped: { + backgroundColor: "#0088ff", + boxShadow: "inset -2px -2px 5px 0px #ffffffaa, inset 2px 2px 5px 0px #ffffffaa" + }, + layer: { + // dimension of the slot, including spaces outside of the box + boxSizing: "border-box", + width: "72px", + height: "72px", + position: "absolute", + top: 0, + left: 0, + }, + // container for the image + image: { + padding: "4px", + }, + imageTranslucent: { + opacity: 0.6, + }, + // The "xCOUNT" text + itemCount: { + fontFamily: "CalamitySans", + fontSize: "10pt", + position: "absolute", + left: "10px", + top: "48px", + color: "#eeeeee", + }, + itemCountShadow: { + // make it more readable over the image + textShadow: "1px 1px #000000", + }, + overlayText: { + color: "#eeeeee", + backgroundColor: "#333b", + boxSizing: "border-box", + border: "1px solid #999999", + position: "absolute", + display: "flex", + minWidth: "20px", + height: "20px", + "& span": { + position: "relative", + display: "inline-block", + top: "1px", + flex: "1", + textAlign: "center", + } + }, + durability: { + padding: "0px 2px", + left: "2px", + bottom: "2px", + }, + holding: { + position: "absolute", + top: "8px", + left: "8px", + display: "flex", + gap: "1px", + }, + holdingElement: { + backgroundColor: "#ffee00", + display: "block", + width: "8px", + height: "8px", + borderRadius: "4px", + border: "1px solid #333333", + }, + entangle: { + color: "#b7f1ff", + display: "flex", + alignItems: "center", + justifyContent: "center", + filter: "drop-shadow(0 0 5px #3aa0ff)", + position: "absolute", + bottom: "0px", + right: "4px", + }, + entangleAnimation: { + animationDuration: "1s", + animationIterationCount: "infinite", + animationName: { + "0%": { + opacity: 1, + }, + "50%": { + opacity: 0, + }, + } + }, + modifierOverlay: { + top: "2px", + left: "2px", + }, + modifier: { + position: "relative", + top: "-1px", + left: "-1px", + width: "18px", + }, + modifierText: { + paddingRight: "2px", + color: "#64E793", + }, + modifierTextBeginPad: { + paddingLeft: "2px", + } +}); + +export type ItemSlotProps = { + info: ItemSlotInfo; +} & Pick; + +/** The Item slot display */ +export const ItemSlot: React.FC = ({ info, cheap, deactive, disableAnimation }) => { + const styles = useStyles(); + const { + actorName, + modEffectId, + itemType, + value, + isEquipped, + isInBrokenSlot, + isInInventory, + holdingCount, + promptEntangled + } = info; + + disableAnimation = disableAnimation || cheap; + + const canStack = getActorParam(actorName, "canStack"); + + const isEquipment = itemType === PouchItemType.Sword || itemType === PouchItemType.Shield || itemType === PouchItemType.Bow; + const badlyDamaged = isEquipment && value < 300; + + const modifier = getModifierInfo(info); + return ( +
+ {/* Background & box*/} +
+
+
0 ? styles.boxInsideHighlightBorder : styles.boxInsideBorder, + isEquipped && styles.equipped + )} >
+
+
+ +
+ {holdingCount > 0 && +
+ {/* Using DOM instead of Unicode, in case user is missing font */} +
+ { + Array.from({ length: holdingCount }).map((_, i) => ( + + )) + } +
+
+ } + { + isEquipment && +
+ + {formatDurability(value)} + + +
+ } + { + // > 1 for displaying corrupted stacks + !isEquipment && (canStack || value > 1) && +
+ x{value} +
+ + } + { + promptEntangled &&<> +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+ + } + { + (!!modifier.iconValue || modifier.status !== SpecialStatus.None) && ( +
+ + { + modifier.status !== SpecialStatus.None && modifier.statusIcon && ( +
+ +
+ ) + } + { + modifier.iconValue && ( + {modifier.iconValue} + ) + } +
+
+ ) + } +
+ ); +}; + +const formatDurability = (value: number): string => { + const durability = value / 100; + if (Number.isInteger(durability)) { + return durability.toString(); + } + return durability.toFixed(2); +} diff --git a/packages/item-system/src/ItemTooltip.tsx b/packages/item-system/src/ItemTooltip.tsx new file mode 100644 index 0000000..2b883ff --- /dev/null +++ b/packages/item-system/src/ItemTooltip.tsx @@ -0,0 +1,29 @@ +import React, { + useEffect, + useState, + PropsWithChildren, +} from "react"; + +import type { ItemTooltipContentProps } from "./ItemTooltipContent.tsx"; +import { useSetItemTooltip } from "./ItemTooltipProvider.tsx"; + +/** Wrapper to show tooltip for an ItemSlot */ +export const ItemTooltip: React.FC> = ({ + info, + children, +}) => { + const setTooltip = useSetItemTooltip(); + + return ( + { + setTooltip(e.clientX, e.clientY, info); + }} + onMouseLeave={() => { + setTooltip(-1, -1, undefined); + }} + > + {children} + + ); +}; diff --git a/packages/item-system/src/ItemTooltipContent.tsx b/packages/item-system/src/ItemTooltipContent.tsx new file mode 100644 index 0000000..20f9baa --- /dev/null +++ b/packages/item-system/src/ItemTooltipContent.tsx @@ -0,0 +1,222 @@ +import { makeStyles, mergeClasses } from "@griffel/react"; +import { Text } from "@fluentui/react-components"; + +import { ModifierSprite, useStaticAssetStyles } from "skybook-item-assets"; +import { useGeneratedTranslation, useUITranslation } from "skybook-localization"; +import type { ItemSlotInfo } from "./data/ItemSlotInfo.ts"; +import { CookEffect, effectToStatus, ItemUse, PouchItemType, SpecialStatus } from "./data/enums.ts"; +import { getActorParam } from "./data/ActorData.ts"; +import { Star16Filled, Star20Filled } from "@fluentui/react-icons"; +import { getModifierInfo } from "./data/ModifierInfo.ts"; + +export type ItemTooltipContentProps = { + info: ItemSlotInfo; +} + +const useStyles = makeStyles({ + text: { + color: "white", + } +}); + +export const ItemTooltipContent: React.FC = +({ info }) => { + const staticAssets = useStaticAssetStyles(); + const styles = useStyles(); + + const t = useGeneratedTranslation(); + const ui = useUITranslation(); + const { actorName, modEffectId, value, isEquipped, isInInventory + ,holdingCount, itemType,itemUse, modEffectValue, modEffectLevel, + modEffectDuration ,modSellPrice + } = info; + + let nameTranslationArgs; + const cookEffectName = CookEffect[modEffectId]; + if (cookEffectName && modEffectId > 0) { + nameTranslationArgs = { + effect: t(`cook.${cookEffectName}.name`), + effect_feminine: t(`cook.${cookEffectName}.name_feminine`), + effect_masculine: t(`cook.${cookEffectName}.name_masculine`), + effect_neuter: t(`cook.${cookEffectName}.name_neuter`), + effect_plural: t(`cook.${cookEffectName}.name_plural`), + }; + } else { + nameTranslationArgs = { + effect: "", + effect_femenine: "", + effect_masculine: "", + effect_neuter: "", + effect_plural: "", + }; + } + + const starNum = getActorParam(actorName, "armorStarNum"); + const isEquipment = itemType === PouchItemType.Sword || itemType === PouchItemType.Bow ||itemType === PouchItemType.Shield; + const isFood = itemType === PouchItemType.Food; + const modifier = getModifierInfo(info); + + const foodStatus = effectToStatus(modEffectId); + + return ( +
+
+ + {t(`actor.${actorName}.name`, nameTranslationArgs)} + {starNum > 1 && Array.from({length: starNum - 1}).map((_, i) => ( + + ))} + + + {actorName} + + + {ui("tooltip.value", { value })} + + { + isEquipped && ( + + {ui("tooltip.equipped")} + + ) + } + { + !isInInventory && ( + + {ui("tooltip.translucent")} + + ) + } + { + holdingCount > 0 && ( + + {ui("tooltip.holding", { holding: holdingCount })} + + ) + } + { + isEquipment && modifier.details.map(({status,statusIcon, modifierValue}, i) => ( + + + + {t(`status.${SpecialStatus[status]}`, { modifier_value: modifierValue })} + + + )) + } + { + // Hearts + isFood && ( + + + { + modEffectId === CookEffect.LifeMaxUp ? ( + <> + + +{modEffectValue}{" "} + { + t(`status.${SpecialStatus[foodStatus]}`) + } + + ) : ( + <> + + +{modEffectValue / 4} + + ) + } + + + ) + } + { + // Stamina/Endura + isFood && (modEffectId === CookEffect.GutsRecover || modEffectId===CookEffect.ExGutsMaxUp) && ( + + + + +{modEffectLevel}{" "} + { + t(`status.${SpecialStatus[foodStatus]}`) + } + + + ) + } + { + // Timed effects + isFood && ( + modEffectId !== CookEffect.None + && modEffectId !== CookEffect.LifeMaxUp + && modEffectId !== CookEffect.LifeRecover + && modEffectId !== CookEffect.GutsRecover + && modEffectId !== CookEffect.ExGutsMaxUp) && ( + + + { + (modEffectLevel < 4 && Number.isInteger(modEffectLevel)) ? ( + (Array.from({length: modEffectLevel})).map((_, i) => ( + + )) + ) : ( + <> + + Lv. {modEffectLevel} + + ) + } + { + t(`status.${SpecialStatus[foodStatus]}`) + } + { + modEffectDuration >= 3600 ? + new Date(modEffectDuration * 1000).toLocaleTimeString("en-US", { + timeZone: "UTC", + hour12: false, + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }) + : + new Date(modEffectDuration * 1000).toLocaleTimeString("en-US", { + timeZone: "UTC", + hour12: false, + minute: "2-digit", + second: "2-digit", + }) + } + + + ) + } + { + isFood && ( + + {ui("tooltip.cook.price", { price: modSellPrice })} + + ) + } + + { + itemType in PouchItemType ? PouchItemType[itemType] : "???" + } + {`[${itemType}]/`} + { + itemUse in ItemUse ? ItemUse[itemUse] : "???" + } + {`[${itemUse}]`} + + + {getActorParam(actorName, "profile")} + + +
+
+
+
+
+
+
+
+ ) +}; diff --git a/packages/item-system/src/ItemTooltipProvider.tsx b/packages/item-system/src/ItemTooltipProvider.tsx new file mode 100644 index 0000000..ec71c71 --- /dev/null +++ b/packages/item-system/src/ItemTooltipProvider.tsx @@ -0,0 +1,91 @@ +import { type PropsWithChildren, createContext, useRef, useState, useCallback, useEffect, useContext, useLayoutEffect, Suspense } from "react"; +import { makeStyles, mergeClasses } from "@griffel/react"; + +import { useStaticAssetStyles } from "skybook-item-assets"; + +import type { ItemSlotInfo } from "./data/ItemSlotInfo.ts"; +import { ItemTooltipContent } from "./ItemTooltipContent.tsx"; + +export type SetItemTooltipFn = (x: number, y: number, info: ItemSlotInfo | undefined) => void; + +const useStyles = makeStyles({ + container: { + position: "absolute", + } +}); + +const ItemTooltipContext = createContext(() => { + /* empty */ +}); + +/** Provider for the ItemTooltipContext */ +export const ItemTooltipProvider: React.FC = ({ children }) => { + const staticAssets = useStaticAssetStyles(); + const styles = useStyles(); + + const toolTipDivRef = useRef(null); + const [tooltipInfo, setTooltipInfo] = useState(); + const setTooltip: SetItemTooltipFn = useCallback( + (x , y, info) => { + if (!toolTipDivRef.current) { + return; + } + const tooltipDiv = toolTipDivRef.current; + if (info === undefined) { + tooltipDiv.style.display = "none"; + return; + } + tooltipDiv.style.display = "unset"; + // This might initially be wrong the first time + // the info is changed. However, most of the time, it will be + // called again with the correct x and y when the mouse moves. + positionTooltipDiv(tooltipDiv, x, y); + setTooltipInfo(info); + }, + [tooltipInfo], + ); + + return ( + + {children} +
+ {tooltipInfo && } +
+
+ ); +}; + +const positionTooltipDiv = (tooltipDiv: HTMLDivElement, x: number, y: number) => { + x += 10; + y += 10; + const oldX = x; + const oldY = y; + tooltipDiv.style.left = `${x}px`; + tooltipDiv.style.top = `${y}px`; + const rect = tooltipDiv.getBoundingClientRect(); + if (rect.bottom > window.innerHeight) { + y -= rect.height + 20; + } + if (rect.right > window.innerWidth) { + x -= rect.width + 20; + } + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x !== oldX) { + tooltipDiv.style.left = `${x}px`; + } + if (y !== oldY) { + tooltipDiv.style.top = `${y}px`; + } +} + +export const useSetItemTooltip = () => { + return useContext(ItemTooltipContext); +} diff --git a/packages/item-system/src/data/ActorData.gen.ts b/packages/item-system/src/data/ActorData.gen.ts new file mode 100644 index 0000000..150f5af --- /dev/null +++ b/packages/item-system/src/data/ActorData.gen.ts @@ -0,0 +1,8 @@ + +/** + * This file is generated by generate-param.py + * DO NOT EDIT MANUALLY + */ +import type { ActorData } from "./ActorData.ts"; + +export const ActorDataMap: Record> = JSON.parse(`{"AncientArrow":{"attackPower":50,"canStack":true,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":90,"profile":"Bullet"},"Animal_Fish_A":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"CapturedActor"},"Animal_Fish_B":{"canStack":true,"generalLife":1,"itemBuyingPrice":72,"itemSellingPrice":18,"profile":"CapturedActor"},"Animal_Fish_C":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"CapturedActor"},"Animal_Fish_D":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"CapturedActor"},"Animal_Fish_E":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_F":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_G":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_H":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_J":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"CapturedActor"},"Animal_Fish_K":{"canStack":true,"generalLife":1,"itemBuyingPrice":60,"itemSellingPrice":15,"profile":"CapturedActor"},"Animal_Fish_L":{"canStack":true,"generalLife":1,"itemBuyingPrice":72,"itemSellingPrice":18,"profile":"CapturedActor"},"Animal_Fish_M":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"CapturedActor"},"Animal_Fish_X":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Animal_Fish_Z":{"canStack":true,"generalLife":1,"itemBuyingPrice":80,"itemSellingPrice":20,"profile":"CapturedActor"},"Animal_Insect_A":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":7,"profile":"CapturedActor"},"Animal_Insect_AA":{"canStack":true,"generalLife":1,"itemBuyingPrice":150,"itemSellingPrice":30,"itemStainColor":3,"profile":"CapturedActor"},"Animal_Insect_AB":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":15,"profile":"CapturedActor"},"Animal_Insect_B":{"canStack":true,"generalLife":1,"itemBuyingPrice":100,"itemSellingPrice":20,"itemStainColor":12,"profile":"CapturedActor"},"Animal_Insect_C":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":1,"profile":"CapturedActor"},"Animal_Insect_E":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":6,"profile":"CapturedActor"},"Animal_Insect_F":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"profile":"CapturedActor"},"Animal_Insect_G":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":4,"itemStainColor":9,"profile":"CapturedActor"},"Animal_Insect_H":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":7,"profile":"CapturedActor"},"Animal_Insect_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":3,"profile":"CapturedActor"},"Animal_Insect_K":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"CapturedActor"},"Animal_Insect_M":{"canStack":true,"generalLife":1,"itemBuyingPrice":100,"itemSellingPrice":20,"itemStainColor":1,"profile":"CapturedActor"},"Animal_Insect_N":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":1,"profile":"CapturedActor"},"Animal_Insect_O":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"CapturedActor"},"Animal_Insect_P":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":4,"itemStainColor":7,"profile":"CapturedActor"},"Animal_Insect_Q":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":2,"profile":"CapturedActor"},"Animal_Insect_R":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":3,"profile":"CapturedActor"},"Animal_Insect_S":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":14,"profile":"CapturedActor"},"Animal_Insect_T":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":2,"itemStainColor":2,"profile":"CapturedActor"},"Animal_Insect_X":{"canStack":true,"generalLife":1,"itemBuyingPrice":25,"itemSellingPrice":5,"itemStainColor":15,"profile":"CapturedActor"},"Animal_Insect_Z":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"CapturedActor"},"Armor_001_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_001_Head_B":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_001_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":90,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorLower"},"Armor_001_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":120,"itemCreatingPrice":0,"itemSellingPrice":30,"profile":"ArmorUpper"},"Armor_002_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":75,"itemCreatingPrice":0,"itemSellingPrice":20,"profile":"ArmorHead"},"Armor_002_Head_B":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":75,"itemCreatingPrice":0,"itemSellingPrice":20,"profile":"ArmorHead"},"Armor_002_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":105,"itemCreatingPrice":0,"itemSellingPrice":30,"profile":"ArmorLower"},"Armor_002_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":135,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorUpper"},"Armor_003_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":139,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorHead"},"Armor_003_Head_B":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":139,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorHead"},"Armor_003_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":169,"itemCreatingPrice":0,"itemSellingPrice":40,"profile":"ArmorLower"},"Armor_003_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":199,"itemCreatingPrice":0,"itemSellingPrice":50,"profile":"ArmorUpper"},"Armor_004_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":319,"itemCreatingPrice":0,"itemSellingPrice":80,"profile":"ArmorHead"},"Armor_004_Head_B":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":319,"itemCreatingPrice":0,"itemSellingPrice":80,"profile":"ArmorHead"},"Armor_004_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":349,"itemCreatingPrice":0,"itemSellingPrice":85,"profile":"ArmorLower"},"Armor_004_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":379,"itemCreatingPrice":0,"itemSellingPrice":95,"profile":"ArmorUpper"},"Armor_005_Head":{"armorDefenceAddLevel":4,"armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorHead"},"Armor_005_Lower":{"armorDefenceAddLevel":4,"armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorLower"},"Armor_005_Upper":{"armorDefenceAddLevel":4,"armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorUpper"},"Armor_006_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorHead","specialStatus":29},"Armor_006_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorLower","specialStatus":29},"Armor_006_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":0,"itemSellingPrice":25,"profile":"ArmorUpper","specialStatus":29},"Armor_007_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":2,"cannotSell":true,"itemBuyingPrice":130,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorHead","specialStatus":29},"Armor_007_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":2,"cannotSell":true,"itemBuyingPrice":130,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorLower","specialStatus":29},"Armor_007_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":2,"cannotSell":true,"itemBuyingPrice":130,"itemCreatingPrice":0,"itemSellingPrice":35,"profile":"ArmorUpper","specialStatus":29},"Armor_008_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistHot","armorStarNum":1,"itemBuyingPrice":450,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorHead","specialStatus":23},"Armor_008_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistHot","armorStarNum":1,"itemBuyingPrice":650,"itemCreatingPrice":0,"itemSellingPrice":165,"profile":"ArmorLower","specialStatus":23},"Armor_008_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistHot","armorStarNum":1,"itemBuyingPrice":1300,"itemCreatingPrice":0,"itemSellingPrice":325,"profile":"ArmorUpper","specialStatus":23},"Armor_009_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistCold","armorStarNum":1,"itemBuyingPrice":1000,"itemCreatingPrice":0,"itemSellingPrice":250,"profile":"ArmorHead","specialStatus":20},"Armor_009_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistCold","armorStarNum":1,"itemBuyingPrice":550,"itemCreatingPrice":0,"itemSellingPrice":140,"profile":"ArmorLower","specialStatus":20},"Armor_009_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistCold","armorStarNum":1,"itemBuyingPrice":600,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorUpper","specialStatus":20},"Armor_011_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistBurn","armorStarNum":1,"itemBuyingPrice":2000,"itemCreatingPrice":0,"itemSellingPrice":500,"profile":"ArmorHead","specialStatus":13},"Armor_011_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistBurn","armorStarNum":1,"itemBuyingPrice":700,"itemCreatingPrice":0,"itemSellingPrice":175,"profile":"ArmorLower","specialStatus":13},"Armor_011_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistBurn","armorStarNum":1,"itemBuyingPrice":600,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorUpper","specialStatus":13},"Armor_012_Head":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":17},"Armor_012_Head_B":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":17},"Armor_012_Lower":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":600,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorLower","specialStatus":17},"Armor_012_Upper":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":700,"itemCreatingPrice":0,"itemSellingPrice":175,"profile":"ArmorUpper","specialStatus":17},"Armor_014_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ClimbSpeed","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorHead","specialStatus":9},"Armor_014_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ClimbSpeed","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorLower","specialStatus":9},"Armor_014_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ClimbSpeed","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorUpper","specialStatus":9},"Armor_015_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":1069,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorHead"},"Armor_015_Head_B":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":1069,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorHead"},"Armor_015_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":1099,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorLower"},"Armor_015_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":1129,"itemCreatingPrice":0,"itemSellingPrice":280,"profile":"ArmorUpper"},"Armor_017_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":800,"itemSellingPrice":200,"profile":"ArmorHead"},"Armor_017_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":800,"itemSellingPrice":200,"profile":"ArmorLower"},"Armor_017_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":800,"itemSellingPrice":200,"profile":"ArmorUpper"},"Armor_020_Head":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":180,"itemCreatingPrice":0,"itemSellingPrice":45,"profile":"ArmorHead"},"Armor_020_Lower":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":200,"itemCreatingPrice":0,"itemSellingPrice":50,"profile":"ArmorLower"},"Armor_020_Upper":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":250,"itemCreatingPrice":0,"itemSellingPrice":65,"profile":"ArmorUpper"},"Armor_021_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":19},"Armor_021_Lower":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorLower","specialStatus":19},"Armor_021_Upper":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorUpper","specialStatus":19},"Armor_022_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":40,"itemCreatingPrice":0,"itemSellingPrice":9,"profile":"ArmorHead"},"Armor_022_Head_B":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":40,"itemCreatingPrice":0,"itemSellingPrice":9,"profile":"ArmorHead"},"Armor_024_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistAncient","armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":1500,"itemSellingPrice":375,"profile":"ArmorHead","specialStatus":19},"Armor_025_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistCold","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":500,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":20},"Armor_026_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistHot","armorStarNum":1,"itemBuyingPrice":600,"itemCreatingPrice":800,"itemSellingPrice":150,"profile":"ArmorHead","specialStatus":23},"Armor_027_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistElectric","armorStarNum":1,"itemBuyingPrice":400,"itemCreatingPrice":500,"itemSellingPrice":100,"profile":"ArmorHead","specialStatus":21},"Armor_028_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"itemBuyingPrice":150,"itemCreatingPrice":200,"itemSellingPrice":40,"profile":"ArmorHead","specialStatus":29},"Armor_029_Head":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":90,"itemCreatingPrice":100,"itemSellingPrice":25,"profile":"ArmorHead"},"Armor_035_Head":{"armorDefenceAddLevel":7,"armorStarNum":2,"cannotSell":true,"itemBuyingPrice":420,"itemCreatingPrice":0,"itemSellingPrice":105,"profile":"ArmorHead"},"Armor_035_Lower":{"armorDefenceAddLevel":7,"armorStarNum":2,"cannotSell":true,"itemBuyingPrice":420,"itemCreatingPrice":0,"itemSellingPrice":105,"profile":"ArmorLower"},"Armor_035_Upper":{"armorDefenceAddLevel":7,"armorStarNum":2,"cannotSell":true,"itemBuyingPrice":420,"itemCreatingPrice":0,"itemSellingPrice":105,"profile":"ArmorUpper"},"Armor_036_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistCold","armorStarNum":2,"itemBuyingPrice":1015,"itemCreatingPrice":0,"itemSellingPrice":255,"profile":"ArmorHead","specialStatus":20},"Armor_036_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistCold","armorStarNum":2,"itemBuyingPrice":565,"itemCreatingPrice":0,"itemSellingPrice":145,"profile":"ArmorLower","specialStatus":20},"Armor_036_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistCold","armorStarNum":2,"itemBuyingPrice":615,"itemCreatingPrice":0,"itemSellingPrice":155,"profile":"ArmorUpper","specialStatus":20},"Armor_037_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistBurn","armorStarNum":2,"itemBuyingPrice":2015,"itemCreatingPrice":0,"itemSellingPrice":505,"profile":"ArmorHead","specialStatus":13},"Armor_037_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistBurn","armorStarNum":2,"itemBuyingPrice":715,"itemCreatingPrice":0,"itemSellingPrice":180,"profile":"ArmorLower","specialStatus":13},"Armor_037_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistBurn","armorStarNum":2,"itemBuyingPrice":615,"itemCreatingPrice":0,"itemSellingPrice":155,"profile":"ArmorUpper","specialStatus":13},"Armor_039_Head":{"armorDefenceAddLevel":12,"armorStarNum":3,"cannotSell":true,"itemBuyingPrice":880,"itemCreatingPrice":0,"itemSellingPrice":220,"profile":"ArmorHead"},"Armor_039_Lower":{"armorDefenceAddLevel":12,"armorStarNum":3,"cannotSell":true,"itemBuyingPrice":880,"itemCreatingPrice":0,"itemSellingPrice":220,"profile":"ArmorLower"},"Armor_039_Upper":{"armorDefenceAddLevel":12,"armorStarNum":3,"cannotSell":true,"itemBuyingPrice":880,"itemCreatingPrice":0,"itemSellingPrice":220,"profile":"ArmorUpper"},"Armor_040_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistHot","armorStarNum":2,"itemBuyingPrice":465,"itemCreatingPrice":0,"itemSellingPrice":120,"profile":"ArmorHead","specialStatus":23},"Armor_040_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistHot","armorStarNum":2,"itemBuyingPrice":665,"itemCreatingPrice":0,"itemSellingPrice":170,"profile":"ArmorLower","specialStatus":23},"Armor_040_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistHot","armorStarNum":2,"itemBuyingPrice":1315,"itemCreatingPrice":0,"itemSellingPrice":330,"profile":"ArmorUpper","specialStatus":23},"Armor_042_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":512,"itemCreatingPrice":0,"itemSellingPrice":130,"profile":"ArmorHead","specialStatus":17},"Armor_042_Head_B":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":512,"itemCreatingPrice":0,"itemSellingPrice":130,"profile":"ArmorHead","specialStatus":17},"Armor_042_Lower":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":612,"itemCreatingPrice":0,"itemSellingPrice":155,"profile":"ArmorLower","specialStatus":17},"Armor_042_Upper":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":712,"itemCreatingPrice":0,"itemSellingPrice":180,"profile":"ArmorUpper","specialStatus":17},"Armor_043_Lower":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorLower"},"Armor_043_Upper":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorUpper"},"Armor_044_Upper":{"armorDefenceAddLevel":1,"armorEffectEffectType":"ResistCold","armorStarNum":1,"itemBuyingPrice":80,"itemCreatingPrice":0,"itemSellingPrice":20,"profile":"ArmorUpper","specialStatus":20},"Armor_045_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":80,"itemCreatingPrice":0,"itemSellingPrice":19,"profile":"ArmorHead"},"Armor_046_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistElectric","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorHead","specialStatus":21},"Armor_046_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistElectric","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorLower","specialStatus":21},"Armor_046_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistElectric","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorUpper","specialStatus":21},"Armor_048_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorHead","specialStatus":8},"Armor_048_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorLower","specialStatus":8},"Armor_048_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":4000,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorUpper","specialStatus":8},"Armor_049_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SandMove","armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":0,"itemSellingPrice":200,"profile":"ArmorLower","specialStatus":25},"Armor_053_Head":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":180,"itemCreatingPrice":0,"itemSellingPrice":45,"profile":"ArmorHead"},"Armor_053_Lower":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":180,"itemCreatingPrice":0,"itemSellingPrice":45,"profile":"ArmorLower"},"Armor_053_Upper":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":180,"itemCreatingPrice":0,"itemSellingPrice":45,"profile":"ArmorUpper"},"Armor_055_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":120,"itemCreatingPrice":0,"itemSellingPrice":29,"profile":"ArmorHead"},"Armor_056_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":320,"itemCreatingPrice":0,"itemSellingPrice":39,"profile":"ArmorHead"},"Armor_060_Head":{"armorDefenceAddLevel":18,"armorStarNum":4,"cannotSell":true,"itemBuyingPrice":1530,"itemCreatingPrice":0,"itemSellingPrice":385,"profile":"ArmorHead"},"Armor_060_Lower":{"armorDefenceAddLevel":18,"armorStarNum":4,"cannotSell":true,"itemBuyingPrice":1530,"itemCreatingPrice":0,"itemSellingPrice":385,"profile":"ArmorLower"},"Armor_060_Upper":{"armorDefenceAddLevel":18,"armorStarNum":4,"cannotSell":true,"itemBuyingPrice":1530,"itemCreatingPrice":0,"itemSellingPrice":385,"profile":"ArmorUpper"},"Armor_061_Head":{"armorDefenceAddLevel":28,"armorStarNum":5,"cannotSell":true,"itemBuyingPrice":2430,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorHead"},"Armor_061_Lower":{"armorDefenceAddLevel":28,"armorStarNum":5,"cannotSell":true,"itemBuyingPrice":2430,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorLower"},"Armor_061_Upper":{"armorDefenceAddLevel":28,"armorStarNum":5,"cannotSell":true,"itemBuyingPrice":2430,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorUpper"},"Armor_062_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SwimSpeed","armorStarNum":3,"cannotSell":true,"itemBuyingPrice":235,"itemCreatingPrice":0,"itemSellingPrice":60,"profile":"ArmorHead","specialStatus":29},"Armor_062_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SwimSpeed","armorStarNum":3,"cannotSell":true,"itemBuyingPrice":235,"itemCreatingPrice":0,"itemSellingPrice":60,"profile":"ArmorLower","specialStatus":29},"Armor_062_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SwimSpeed","armorStarNum":3,"cannotSell":true,"itemBuyingPrice":235,"itemCreatingPrice":0,"itemSellingPrice":60,"profile":"ArmorUpper","specialStatus":29},"Armor_063_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SwimSpeed","armorStarNum":4,"cannotSell":true,"itemBuyingPrice":465,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorHead","specialStatus":29},"Armor_063_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SwimSpeed","armorStarNum":4,"cannotSell":true,"itemBuyingPrice":465,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorLower","specialStatus":29},"Armor_063_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SwimSpeed","armorStarNum":4,"cannotSell":true,"itemBuyingPrice":465,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorUpper","specialStatus":29},"Armor_064_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SwimSpeed","armorStarNum":5,"cannotSell":true,"itemBuyingPrice":1645,"itemCreatingPrice":0,"itemSellingPrice":410,"profile":"ArmorHead","specialStatus":29},"Armor_064_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SwimSpeed","armorStarNum":5,"cannotSell":true,"itemBuyingPrice":1645,"itemCreatingPrice":0,"itemSellingPrice":410,"profile":"ArmorLower","specialStatus":29},"Armor_064_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SwimSpeed","armorStarNum":5,"cannotSell":true,"itemBuyingPrice":1645,"itemCreatingPrice":0,"itemSellingPrice":410,"profile":"ArmorUpper","specialStatus":29},"Armor_065_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistHot","armorStarNum":3,"itemBuyingPrice":508,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":23},"Armor_065_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistHot","armorStarNum":3,"itemBuyingPrice":708,"itemCreatingPrice":0,"itemSellingPrice":175,"profile":"ArmorLower","specialStatus":23},"Armor_065_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistHot","armorStarNum":3,"itemBuyingPrice":1358,"itemCreatingPrice":0,"itemSellingPrice":340,"profile":"ArmorUpper","specialStatus":23},"Armor_066_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistHot","armorStarNum":4,"itemBuyingPrice":661,"itemCreatingPrice":0,"itemSellingPrice":165,"profile":"ArmorHead","specialStatus":23},"Armor_066_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistHot","armorStarNum":4,"itemBuyingPrice":861,"itemCreatingPrice":0,"itemSellingPrice":215,"profile":"ArmorLower","specialStatus":23},"Armor_066_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistHot","armorStarNum":4,"itemBuyingPrice":1511,"itemCreatingPrice":0,"itemSellingPrice":380,"profile":"ArmorUpper","specialStatus":23},"Armor_067_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistHot","armorStarNum":5,"itemBuyingPrice":2311,"itemCreatingPrice":0,"itemSellingPrice":580,"profile":"ArmorHead","specialStatus":23},"Armor_067_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistHot","armorStarNum":5,"itemBuyingPrice":2511,"itemCreatingPrice":0,"itemSellingPrice":630,"profile":"ArmorLower","specialStatus":23},"Armor_067_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistHot","armorStarNum":5,"itemBuyingPrice":3161,"itemCreatingPrice":0,"itemSellingPrice":800,"profile":"ArmorUpper","specialStatus":23},"Armor_071_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistCold","armorStarNum":3,"itemBuyingPrice":1049,"itemCreatingPrice":0,"itemSellingPrice":260,"profile":"ArmorHead","specialStatus":20},"Armor_071_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistCold","armorStarNum":3,"itemBuyingPrice":599,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorLower","specialStatus":20},"Armor_071_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistCold","armorStarNum":3,"itemBuyingPrice":649,"itemCreatingPrice":0,"itemSellingPrice":160,"profile":"ArmorUpper","specialStatus":20},"Armor_072_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistCold","armorStarNum":4,"itemBuyingPrice":1117,"itemCreatingPrice":0,"itemSellingPrice":280,"profile":"ArmorHead","specialStatus":20},"Armor_072_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistCold","armorStarNum":4,"itemBuyingPrice":699,"itemCreatingPrice":0,"itemSellingPrice":165,"profile":"ArmorLower","specialStatus":20},"Armor_072_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistCold","armorStarNum":4,"itemBuyingPrice":749,"itemCreatingPrice":0,"itemSellingPrice":185,"profile":"ArmorUpper","specialStatus":20},"Armor_073_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistCold","armorStarNum":5,"itemBuyingPrice":2517,"itemCreatingPrice":0,"itemSellingPrice":630,"profile":"ArmorHead","specialStatus":20},"Armor_073_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistCold","armorStarNum":5,"itemBuyingPrice":2067,"itemCreatingPrice":0,"itemSellingPrice":515,"profile":"ArmorLower","specialStatus":20},"Armor_073_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistCold","armorStarNum":5,"itemBuyingPrice":2117,"itemCreatingPrice":0,"itemSellingPrice":530,"profile":"ArmorUpper","specialStatus":20},"Armor_074_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistBurn","armorStarNum":3,"itemBuyingPrice":2078,"itemCreatingPrice":0,"itemSellingPrice":520,"profile":"ArmorHead","specialStatus":13},"Armor_074_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistBurn","armorStarNum":3,"itemBuyingPrice":778,"itemCreatingPrice":0,"itemSellingPrice":195,"profile":"ArmorLower","specialStatus":13},"Armor_074_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistBurn","armorStarNum":3,"itemBuyingPrice":678,"itemCreatingPrice":0,"itemSellingPrice":170,"profile":"ArmorUpper","specialStatus":13},"Armor_075_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistBurn","armorStarNum":4,"itemBuyingPrice":2183,"itemCreatingPrice":0,"itemSellingPrice":545,"profile":"ArmorHead","specialStatus":13},"Armor_075_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistBurn","armorStarNum":4,"itemBuyingPrice":883,"itemCreatingPrice":0,"itemSellingPrice":220,"profile":"ArmorLower","specialStatus":13},"Armor_075_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistBurn","armorStarNum":4,"itemBuyingPrice":783,"itemCreatingPrice":0,"itemSellingPrice":195,"profile":"ArmorUpper","specialStatus":13},"Armor_076_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistBurn","armorStarNum":5,"itemBuyingPrice":2393,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorHead","specialStatus":13},"Armor_076_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistBurn","armorStarNum":5,"itemBuyingPrice":1093,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorLower","specialStatus":13},"Armor_076_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistBurn","armorStarNum":5,"itemBuyingPrice":993,"itemCreatingPrice":0,"itemSellingPrice":250,"profile":"ArmorUpper","specialStatus":13},"Armor_077_Head":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":542,"itemCreatingPrice":0,"itemSellingPrice":135,"profile":"ArmorHead","specialStatus":17},"Armor_077_Head_B":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":542,"itemCreatingPrice":0,"itemSellingPrice":135,"profile":"ArmorHead","specialStatus":17},"Armor_077_Lower":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":642,"itemCreatingPrice":0,"itemSellingPrice":160,"profile":"ArmorLower","specialStatus":17},"Armor_077_Upper":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":742,"itemCreatingPrice":0,"itemSellingPrice":185,"profile":"ArmorUpper","specialStatus":17},"Armor_078_Head":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":596,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorHead","specialStatus":17},"Armor_078_Head_B":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":596,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorHead","specialStatus":17},"Armor_078_Lower":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":696,"itemCreatingPrice":0,"itemSellingPrice":175,"profile":"ArmorLower","specialStatus":17},"Armor_078_Upper":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":796,"itemCreatingPrice":0,"itemSellingPrice":200,"profile":"ArmorUpper","specialStatus":17},"Armor_079_Head":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":896,"itemCreatingPrice":0,"itemSellingPrice":225,"profile":"ArmorHead","specialStatus":17},"Armor_079_Head_B":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":896,"itemCreatingPrice":0,"itemSellingPrice":225,"profile":"ArmorHead","specialStatus":17},"Armor_079_Lower":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":996,"itemCreatingPrice":0,"itemSellingPrice":250,"profile":"ArmorLower","specialStatus":17},"Armor_079_Upper":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":1095,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorUpper","specialStatus":17},"Armor_083_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ClimbSpeed","armorStarNum":2,"itemBuyingPrice":4018,"itemCreatingPrice":0,"itemSellingPrice":605,"profile":"ArmorHead","specialStatus":9},"Armor_083_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ClimbSpeed","armorStarNum":2,"itemBuyingPrice":4018,"itemCreatingPrice":0,"itemSellingPrice":605,"profile":"ArmorLower","specialStatus":9},"Armor_083_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ClimbSpeed","armorStarNum":2,"itemBuyingPrice":4018,"itemCreatingPrice":0,"itemSellingPrice":605,"profile":"ArmorUpper","specialStatus":9},"Armor_084_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ClimbSpeed","armorStarNum":3,"itemBuyingPrice":4060,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorHead","specialStatus":9},"Armor_084_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ClimbSpeed","armorStarNum":3,"itemBuyingPrice":4060,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorLower","specialStatus":9},"Armor_084_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ClimbSpeed","armorStarNum":3,"itemBuyingPrice":4060,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorUpper","specialStatus":9},"Armor_085_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ClimbSpeed","armorStarNum":4,"itemBuyingPrice":4120,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorHead","specialStatus":9},"Armor_085_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ClimbSpeed","armorStarNum":4,"itemBuyingPrice":4120,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorLower","specialStatus":9},"Armor_085_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ClimbSpeed","armorStarNum":4,"itemBuyingPrice":4120,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorUpper","specialStatus":9},"Armor_086_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ClimbSpeed","armorStarNum":5,"itemBuyingPrice":4300,"itemCreatingPrice":0,"itemSellingPrice":645,"profile":"ArmorHead","specialStatus":9},"Armor_086_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ClimbSpeed","armorStarNum":5,"itemBuyingPrice":4300,"itemCreatingPrice":0,"itemSellingPrice":645,"profile":"ArmorLower","specialStatus":9},"Armor_086_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ClimbSpeed","armorStarNum":5,"itemBuyingPrice":4300,"itemCreatingPrice":0,"itemSellingPrice":645,"profile":"ArmorUpper","specialStatus":9},"Armor_087_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":1210,"itemCreatingPrice":0,"itemSellingPrice":305,"profile":"ArmorHead"},"Armor_087_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":1210,"itemCreatingPrice":0,"itemSellingPrice":305,"profile":"ArmorLower"},"Armor_087_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":1210,"itemCreatingPrice":0,"itemSellingPrice":305,"profile":"ArmorUpper"},"Armor_088_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":1845,"itemCreatingPrice":0,"itemSellingPrice":460,"profile":"ArmorHead"},"Armor_088_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":1845,"itemCreatingPrice":0,"itemSellingPrice":460,"profile":"ArmorLower"},"Armor_088_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":1845,"itemCreatingPrice":0,"itemSellingPrice":460,"profile":"ArmorUpper"},"Armor_089_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":2765,"itemCreatingPrice":0,"itemSellingPrice":690,"profile":"ArmorHead"},"Armor_089_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":2765,"itemCreatingPrice":0,"itemSellingPrice":690,"profile":"ArmorLower"},"Armor_089_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":2765,"itemCreatingPrice":0,"itemSellingPrice":690,"profile":"ArmorUpper"},"Armor_090_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":4365,"itemCreatingPrice":0,"itemSellingPrice":1090,"profile":"ArmorHead"},"Armor_090_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":4365,"itemCreatingPrice":0,"itemSellingPrice":1090,"profile":"ArmorLower"},"Armor_090_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":4365,"itemCreatingPrice":0,"itemSellingPrice":1090,"profile":"ArmorUpper"},"Armor_095_Head":{"armorDefenceAddLevel":7,"armorStarNum":2,"itemBuyingPrice":250,"itemCreatingPrice":0,"itemSellingPrice":65,"profile":"ArmorHead"},"Armor_095_Lower":{"armorDefenceAddLevel":7,"armorStarNum":2,"itemBuyingPrice":270,"itemCreatingPrice":0,"itemSellingPrice":70,"profile":"ArmorLower"},"Armor_095_Upper":{"armorDefenceAddLevel":7,"armorStarNum":2,"itemBuyingPrice":320,"itemCreatingPrice":0,"itemSellingPrice":80,"profile":"ArmorUpper"},"Armor_096_Head":{"armorDefenceAddLevel":12,"armorStarNum":3,"itemBuyingPrice":385,"itemCreatingPrice":0,"itemSellingPrice":95,"profile":"ArmorHead"},"Armor_096_Lower":{"armorDefenceAddLevel":12,"armorStarNum":3,"itemBuyingPrice":405,"itemCreatingPrice":0,"itemSellingPrice":100,"profile":"ArmorLower"},"Armor_096_Upper":{"armorDefenceAddLevel":12,"armorStarNum":3,"itemBuyingPrice":455,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorUpper"},"Armor_097_Head":{"armorDefenceAddLevel":18,"armorStarNum":4,"itemBuyingPrice":601,"itemCreatingPrice":0,"itemSellingPrice":150,"profile":"ArmorHead"},"Armor_097_Lower":{"armorDefenceAddLevel":18,"armorStarNum":4,"itemBuyingPrice":569,"itemCreatingPrice":0,"itemSellingPrice":140,"profile":"ArmorLower"},"Armor_097_Upper":{"armorDefenceAddLevel":18,"armorStarNum":4,"itemBuyingPrice":619,"itemCreatingPrice":0,"itemSellingPrice":155,"profile":"ArmorUpper"},"Armor_098_Head":{"armorDefenceAddLevel":28,"armorStarNum":5,"itemBuyingPrice":1101,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorHead"},"Armor_098_Lower":{"armorDefenceAddLevel":28,"armorStarNum":5,"itemBuyingPrice":1069,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorLower"},"Armor_098_Upper":{"armorDefenceAddLevel":28,"armorStarNum":5,"itemBuyingPrice":1169,"itemCreatingPrice":0,"itemSellingPrice":290,"profile":"ArmorUpper"},"Armor_099_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorHead","specialStatus":19},"Armor_099_Lower":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorLower","specialStatus":19},"Armor_099_Upper":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorUpper","specialStatus":19},"Armor_100_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorHead","specialStatus":19},"Armor_100_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorLower","specialStatus":19},"Armor_100_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorUpper","specialStatus":19},"Armor_101_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorHead","specialStatus":19},"Armor_101_Lower":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorLower","specialStatus":19},"Armor_101_Upper":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorUpper","specialStatus":19},"Armor_102_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorHead","specialStatus":19},"Armor_102_Lower":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorLower","specialStatus":19},"Armor_102_Upper":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorUpper","specialStatus":19},"Armor_103_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistElectric","armorStarNum":2,"itemBuyingPrice":4015,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorHead","specialStatus":21},"Armor_103_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistElectric","armorStarNum":2,"itemBuyingPrice":4015,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorLower","specialStatus":21},"Armor_103_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistElectric","armorStarNum":2,"itemBuyingPrice":4015,"itemCreatingPrice":0,"itemSellingPrice":600,"profile":"ArmorUpper","specialStatus":21},"Armor_104_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistElectric","armorStarNum":3,"itemBuyingPrice":4058,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorHead","specialStatus":21},"Armor_104_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistElectric","armorStarNum":3,"itemBuyingPrice":4058,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorLower","specialStatus":21},"Armor_104_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistElectric","armorStarNum":3,"itemBuyingPrice":4058,"itemCreatingPrice":0,"itemSellingPrice":610,"profile":"ArmorUpper","specialStatus":21},"Armor_105_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistElectric","armorStarNum":4,"itemBuyingPrice":4253,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorHead","specialStatus":21},"Armor_105_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistElectric","armorStarNum":4,"itemBuyingPrice":4253,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorLower","specialStatus":21},"Armor_105_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistElectric","armorStarNum":4,"itemBuyingPrice":4253,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorUpper","specialStatus":21},"Armor_106_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistElectric","armorStarNum":5,"itemBuyingPrice":6403,"itemCreatingPrice":0,"itemSellingPrice":960,"profile":"ArmorHead","specialStatus":21},"Armor_106_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistElectric","armorStarNum":5,"itemBuyingPrice":6403,"itemCreatingPrice":0,"itemSellingPrice":960,"profile":"ArmorLower","specialStatus":21},"Armor_106_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistElectric","armorStarNum":5,"itemBuyingPrice":6403,"itemCreatingPrice":0,"itemSellingPrice":960,"profile":"ArmorUpper","specialStatus":21},"Armor_111_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":4040,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorHead","specialStatus":8},"Armor_111_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":4040,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorLower","specialStatus":8},"Armor_111_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":4040,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorUpper","specialStatus":8},"Armor_112_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":4260,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorHead","specialStatus":8},"Armor_112_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":4260,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorLower","specialStatus":8},"Armor_112_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":4260,"itemCreatingPrice":0,"itemSellingPrice":640,"profile":"ArmorUpper","specialStatus":8},"Armor_113_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":4660,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorHead","specialStatus":8},"Armor_113_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":4660,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorLower","specialStatus":8},"Armor_113_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":4660,"itemCreatingPrice":0,"itemSellingPrice":700,"profile":"ArmorUpper","specialStatus":8},"Armor_114_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":5360,"itemCreatingPrice":0,"itemSellingPrice":805,"profile":"ArmorHead","specialStatus":8},"Armor_114_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":5360,"itemCreatingPrice":0,"itemSellingPrice":805,"profile":"ArmorLower","specialStatus":8},"Armor_114_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":5360,"itemCreatingPrice":0,"itemSellingPrice":805,"profile":"ArmorUpper","specialStatus":8},"Armor_115_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistLightning","armorStarNum":1,"cannotSell":true,"itemBuyingPrice":1000,"itemCreatingPrice":0,"itemSellingPrice":250,"profile":"ArmorHead","specialStatus":24},"Armor_116_Upper":{"armorDefenceAddLevel":5,"armorStarNum":1,"cannotSell":true,"itemBuyingPrice":1000,"itemCreatingPrice":0,"itemSellingPrice":250,"profile":"ArmorUpper"},"Armor_117_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistAncient","armorStarNum":2,"itemBuyingPrice":1800,"itemCreatingPrice":0,"itemSellingPrice":630,"profile":"ArmorHead","specialStatus":19},"Armor_118_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistAncient","armorStarNum":3,"itemBuyingPrice":3800,"itemCreatingPrice":0,"itemSellingPrice":1135,"profile":"ArmorHead","specialStatus":19},"Armor_119_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistAncient","armorStarNum":4,"itemBuyingPrice":6800,"itemCreatingPrice":0,"itemSellingPrice":1960,"profile":"ArmorHead","specialStatus":19},"Armor_120_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistAncient","armorStarNum":5,"itemBuyingPrice":11800,"itemCreatingPrice":0,"itemSellingPrice":3285,"profile":"ArmorHead","specialStatus":19},"Armor_121_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistCold","armorStarNum":2,"itemBuyingPrice":935,"itemCreatingPrice":0,"itemSellingPrice":235,"profile":"ArmorHead","specialStatus":20},"Armor_122_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistCold","armorStarNum":3,"itemBuyingPrice":1790,"itemCreatingPrice":0,"itemSellingPrice":450,"profile":"ArmorHead","specialStatus":20},"Armor_123_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistCold","armorStarNum":4,"itemBuyingPrice":3350,"itemCreatingPrice":0,"itemSellingPrice":840,"profile":"ArmorHead","specialStatus":20},"Armor_124_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistCold","armorStarNum":5,"itemBuyingPrice":5750,"itemCreatingPrice":0,"itemSellingPrice":1440,"profile":"ArmorHead","specialStatus":20},"Armor_125_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistHot","armorStarNum":2,"itemBuyingPrice":1135,"itemCreatingPrice":0,"itemSellingPrice":285,"profile":"ArmorHead","specialStatus":23},"Armor_126_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistHot","armorStarNum":3,"itemBuyingPrice":2190,"itemCreatingPrice":0,"itemSellingPrice":550,"profile":"ArmorHead","specialStatus":23},"Armor_127_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistHot","armorStarNum":4,"itemBuyingPrice":4050,"itemCreatingPrice":0,"itemSellingPrice":1015,"profile":"ArmorHead","specialStatus":23},"Armor_128_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"ResistHot","armorStarNum":5,"itemBuyingPrice":6950,"itemCreatingPrice":0,"itemSellingPrice":1740,"profile":"ArmorHead","specialStatus":23},"Armor_129_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"ResistElectric","armorStarNum":2,"itemBuyingPrice":775,"itemCreatingPrice":0,"itemSellingPrice":195,"profile":"ArmorHead","specialStatus":21},"Armor_130_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"ResistElectric","armorStarNum":3,"itemBuyingPrice":1510,"itemCreatingPrice":0,"itemSellingPrice":380,"profile":"ArmorHead","specialStatus":21},"Armor_131_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistElectric","armorStarNum":4,"itemBuyingPrice":2890,"itemCreatingPrice":0,"itemSellingPrice":725,"profile":"ArmorHead","specialStatus":21},"Armor_132_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistElectric","armorStarNum":5,"itemBuyingPrice":4990,"itemCreatingPrice":0,"itemSellingPrice":1250,"profile":"ArmorHead","specialStatus":21},"Armor_133_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":2,"itemBuyingPrice":465,"itemCreatingPrice":0,"itemSellingPrice":115,"profile":"ArmorHead","specialStatus":29},"Armor_134_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SwimSpeed","armorStarNum":3,"itemBuyingPrice":960,"itemCreatingPrice":0,"itemSellingPrice":240,"profile":"ArmorHead","specialStatus":29},"Armor_135_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SwimSpeed","armorStarNum":4,"itemBuyingPrice":1935,"itemCreatingPrice":0,"itemSellingPrice":485,"profile":"ArmorHead","specialStatus":29},"Armor_136_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SwimSpeed","armorStarNum":5,"itemBuyingPrice":3150,"itemCreatingPrice":0,"itemSellingPrice":790,"profile":"ArmorHead","specialStatus":29},"Armor_137_Head":{"armorDefenceAddLevel":7,"armorStarNum":2,"itemBuyingPrice":255,"itemCreatingPrice":0,"itemSellingPrice":65,"profile":"ArmorHead"},"Armor_138_Head":{"armorDefenceAddLevel":12,"armorStarNum":3,"itemBuyingPrice":570,"itemCreatingPrice":0,"itemSellingPrice":145,"profile":"ArmorHead"},"Armor_139_Head":{"armorDefenceAddLevel":18,"armorStarNum":4,"itemBuyingPrice":1185,"itemCreatingPrice":0,"itemSellingPrice":295,"profile":"ArmorHead"},"Armor_140_Head":{"armorDefenceAddLevel":28,"armorStarNum":5,"itemBuyingPrice":2100,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorHead"},"Armor_140_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SnowMove","armorStarNum":1,"cannotSell":true,"itemBuyingPrice":800,"itemCreatingPrice":0,"itemSellingPrice":200,"profile":"ArmorLower","specialStatus":26},"Armor_141_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"SnowMove","armorStarNum":1,"itemBuyingPrice":800,"itemCreatingPrice":0,"itemSellingPrice":200,"profile":"ArmorLower","specialStatus":26},"Armor_148_Upper":{"armorDefenceAddLevel":8,"armorStarNum":2,"cannotSell":true,"itemBuyingPrice":1120,"itemCreatingPrice":0,"itemSellingPrice":280,"profile":"ArmorUpper"},"Armor_149_Upper":{"armorDefenceAddLevel":14,"armorStarNum":3,"cannotSell":true,"itemBuyingPrice":1840,"itemCreatingPrice":0,"itemSellingPrice":460,"profile":"ArmorUpper"},"Armor_150_Upper":{"armorDefenceAddLevel":22,"armorStarNum":4,"cannotSell":true,"itemBuyingPrice":2640,"itemCreatingPrice":0,"itemSellingPrice":660,"profile":"ArmorUpper"},"Armor_151_Upper":{"armorDefenceAddLevel":32,"armorStarNum":5,"cannotSell":true,"itemBuyingPrice":3640,"itemCreatingPrice":0,"itemSellingPrice":910,"profile":"ArmorUpper"},"Armor_152_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SandMove","armorStarNum":2,"itemBuyingPrice":980,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorLower","specialStatus":25},"Armor_153_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SandMove","armorStarNum":3,"itemBuyingPrice":1320,"itemCreatingPrice":0,"itemSellingPrice":330,"profile":"ArmorLower","specialStatus":25},"Armor_154_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SandMove","armorStarNum":4,"itemBuyingPrice":1585,"itemCreatingPrice":0,"itemSellingPrice":395,"profile":"ArmorLower","specialStatus":25},"Armor_155_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SandMove","armorStarNum":5,"itemBuyingPrice":2175,"itemCreatingPrice":0,"itemSellingPrice":545,"profile":"ArmorLower","specialStatus":25},"Armor_156_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SnowMove","armorStarNum":2,"itemBuyingPrice":870,"itemCreatingPrice":0,"itemSellingPrice":220,"profile":"ArmorLower","specialStatus":26},"Armor_157_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"SnowMove","armorStarNum":3,"itemBuyingPrice":935,"itemCreatingPrice":0,"itemSellingPrice":235,"profile":"ArmorLower","specialStatus":26},"Armor_158_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SnowMove","armorStarNum":4,"itemBuyingPrice":1070,"itemCreatingPrice":0,"itemSellingPrice":270,"profile":"ArmorLower","specialStatus":26},"Armor_159_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"SnowMove","armorStarNum":5,"itemBuyingPrice":1530,"itemCreatingPrice":0,"itemSellingPrice":385,"profile":"ArmorLower","specialStatus":26},"Armor_160_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":40,"itemCreatingPrice":0,"itemSellingPrice":9,"profile":"ArmorHead"},"Armor_160_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":40,"itemCreatingPrice":0,"itemSellingPrice":9,"profile":"ArmorLower"},"Armor_160_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":40,"itemCreatingPrice":0,"itemSellingPrice":9,"profile":"ArmorUpper"},"Armor_168_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistElectricAndResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorHead","specialStatus":21},"Armor_169_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistElectricAndResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorHead","specialStatus":21},"Armor_170_Upper":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorUpper"},"Armor_171_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":8},"Armor_171_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorLower","specialStatus":8},"Armor_171_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorUpper","specialStatus":8},"Armor_172_Head":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_173_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistAncient","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":19},"Armor_174_Head":{"armorDefenceAddLevel":2,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_174_Lower":{"armorDefenceAddLevel":2,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorLower"},"Armor_174_Upper":{"armorDefenceAddLevel":2,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorUpper"},"Armor_175_Upper":{"armorDefenceAddLevel":1,"armorEffectEffectType":"ResistHotAndWakeWind","armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorUpper","specialStatus":23},"Armor_176_Head":{"armorDefenceAddLevel":1,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_177_Head":{"armorDefenceAddLevel":2,"armorEffectEffectType":"ClimbSpeedAndBeamPowerUp","armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":9},"Armor_177_Head_B":{"armorDefenceAddLevel":2,"armorEffectEffectType":"ClimbSpeedAndBeamPowerUp","armorStarNum":1,"itemBuyingPrice":50,"itemCreatingPrice":0,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":9},"Armor_178_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistFreeze","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":22},"Armor_178_Head_B":{"armorDefenceAddLevel":3,"armorEffectEffectType":"ResistFreeze","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":22},"Armor_179_Head":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead"},"Armor_179_Lower":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorLower"},"Armor_179_Upper":{"armorDefenceAddLevel":4,"armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorUpper"},"Armor_180_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":17},"Armor_180_Lower":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorLower","specialStatus":17},"Armor_180_Upper":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorUpper","specialStatus":17},"Armor_181_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"SwimSpeedAndResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":29},"Armor_182_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistColdAndResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":20},"Armor_183_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistBurnAndResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":13},"Armor_184_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"ResistElectricAndResistAncient","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":2000,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":21},"Armor_185_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorHead","specialStatus":29},"Armor_185_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorLower","specialStatus":29},"Armor_185_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"SwimSpeed","armorStarNum":1,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"ArmorUpper","specialStatus":29},"Armor_186_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"SwimSpeedAndResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorHead","specialStatus":29},"Armor_187_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"SwimSpeedAndResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorHead","specialStatus":29},"Armor_188_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"SwimSpeedAndResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorHead","specialStatus":29},"Armor_189_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"SwimSpeedAndResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorHead","specialStatus":29},"Armor_190_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistColdAndResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorHead","specialStatus":20},"Armor_191_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistColdAndResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorHead","specialStatus":20},"Armor_192_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistColdAndResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorHead","specialStatus":20},"Armor_193_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistColdAndResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorHead","specialStatus":20},"Armor_194_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistBurnAndResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorHead","specialStatus":13},"Armor_195_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistBurnAndResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorHead","specialStatus":13},"Armor_196_Head":{"armorDefenceAddLevel":18,"armorEffectEffectType":"ResistBurnAndResistAncient","armorStarNum":4,"itemBuyingPrice":2235,"itemCreatingPrice":5000,"itemSellingPrice":560,"profile":"ArmorHead","specialStatus":13},"Armor_197_Head":{"armorDefenceAddLevel":28,"armorEffectEffectType":"ResistBurnAndResistAncient","armorStarNum":5,"itemBuyingPrice":2935,"itemCreatingPrice":6000,"itemSellingPrice":735,"profile":"ArmorHead","specialStatus":13},"Armor_198_Head":{"armorDefenceAddLevel":7,"armorEffectEffectType":"ResistElectricAndResistAncient","armorStarNum":2,"itemBuyingPrice":635,"itemCreatingPrice":3000,"itemSellingPrice":160,"profile":"ArmorHead","specialStatus":21},"Armor_199_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"ResistElectricAndResistAncient","armorStarNum":3,"itemBuyingPrice":1160,"itemCreatingPrice":4000,"itemSellingPrice":290,"profile":"ArmorHead","specialStatus":21},"Armor_200_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead"},"Armor_200_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower"},"Armor_200_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper"},"Armor_201_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":225,"profile":"ArmorHead"},"Armor_201_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":225,"profile":"ArmorLower"},"Armor_201_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":225,"profile":"ArmorUpper"},"Armor_202_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":335,"profile":"ArmorHead"},"Armor_202_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":335,"profile":"ArmorLower"},"Armor_202_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":335,"profile":"ArmorUpper"},"Armor_203_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorHead"},"Armor_203_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorLower"},"Armor_203_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorUpper"},"Armor_204_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorHead"},"Armor_204_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorLower"},"Armor_204_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorUpper"},"Armor_205_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead"},"Armor_205_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower"},"Armor_205_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper"},"Armor_206_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorHead"},"Armor_206_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorLower"},"Armor_206_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorUpper"},"Armor_207_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":395,"profile":"ArmorHead"},"Armor_207_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":395,"profile":"ArmorLower"},"Armor_207_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":395,"profile":"ArmorUpper"},"Armor_208_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorHead"},"Armor_208_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorLower"},"Armor_208_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":620,"profile":"ArmorUpper"},"Armor_209_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":995,"profile":"ArmorHead"},"Armor_209_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":995,"profile":"ArmorLower"},"Armor_209_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":995,"profile":"ArmorUpper"},"Armor_210_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead"},"Armor_210_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower"},"Armor_210_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper"},"Armor_211_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorHead"},"Armor_211_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorLower"},"Armor_211_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":245,"profile":"ArmorUpper"},"Armor_212_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":455,"profile":"ArmorHead"},"Armor_212_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":455,"profile":"ArmorLower"},"Armor_212_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":455,"profile":"ArmorUpper"},"Armor_213_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":755,"profile":"ArmorHead"},"Armor_213_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":755,"profile":"ArmorLower"},"Armor_213_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":755,"profile":"ArmorUpper"},"Armor_214_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1280,"profile":"ArmorHead"},"Armor_214_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1280,"profile":"ArmorLower"},"Armor_214_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1280,"profile":"ArmorUpper"},"Armor_215_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead"},"Armor_215_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower"},"Armor_215_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper"},"Armor_216_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorHead"},"Armor_216_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorLower"},"Armor_216_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":265,"profile":"ArmorUpper"},"Armor_217_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":535,"profile":"ArmorHead"},"Armor_217_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":535,"profile":"ArmorLower"},"Armor_217_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":535,"profile":"ArmorUpper"},"Armor_218_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":935,"profile":"ArmorHead"},"Armor_218_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":935,"profile":"ArmorLower"},"Armor_218_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":935,"profile":"ArmorUpper"},"Armor_219_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1660,"profile":"ArmorHead"},"Armor_219_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1660,"profile":"ArmorLower"},"Armor_219_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1660,"profile":"ArmorUpper"},"Armor_220_Head":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":17},"Armor_220_Head_B":{"armorDefenceAddLevel":2,"armorEffectEffectType":"Quietness","armorStarNum":1,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":17},"Armor_221_Head":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":210,"profile":"ArmorHead","specialStatus":17},"Armor_221_Head_B":{"armorDefenceAddLevel":4,"armorEffectEffectType":"Quietness","armorStarNum":2,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":210,"profile":"ArmorHead","specialStatus":17},"Armor_222_Head":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":305,"profile":"ArmorHead","specialStatus":17},"Armor_222_Head_B":{"armorDefenceAddLevel":6,"armorEffectEffectType":"Quietness","armorStarNum":3,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":305,"profile":"ArmorHead","specialStatus":17},"Armor_223_Head":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":410,"profile":"ArmorHead","specialStatus":17},"Armor_223_Head_B":{"armorDefenceAddLevel":9,"armorEffectEffectType":"Quietness","armorStarNum":4,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":410,"profile":"ArmorHead","specialStatus":17},"Armor_224_Head":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorHead","specialStatus":17},"Armor_224_Head_B":{"armorDefenceAddLevel":16,"armorEffectEffectType":"Quietness","armorStarNum":5,"itemBuyingPrice":400,"itemCreatingPrice":0,"itemSellingPrice":525,"profile":"ArmorHead","specialStatus":17},"Armor_225_Head":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead","specialStatus":8},"Armor_225_Lower":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower","specialStatus":8},"Armor_225_Upper":{"armorDefenceAddLevel":3,"armorEffectEffectType":"AttackUp","armorStarNum":1,"itemBuyingPrice":500,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper","specialStatus":8},"Armor_226_Head":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":750,"itemCreatingPrice":0,"itemSellingPrice":190,"profile":"ArmorHead","specialStatus":8},"Armor_226_Lower":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":750,"itemCreatingPrice":0,"itemSellingPrice":190,"profile":"ArmorLower","specialStatus":8},"Armor_226_Upper":{"armorDefenceAddLevel":5,"armorEffectEffectType":"AttackUp","armorStarNum":2,"itemBuyingPrice":750,"itemCreatingPrice":0,"itemSellingPrice":190,"profile":"ArmorUpper","specialStatus":8},"Armor_227_Head":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":1105,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorHead","specialStatus":8},"Armor_227_Lower":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":1105,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorLower","specialStatus":8},"Armor_227_Upper":{"armorDefenceAddLevel":8,"armorEffectEffectType":"AttackUp","armorStarNum":3,"itemBuyingPrice":1105,"itemCreatingPrice":0,"itemSellingPrice":275,"profile":"ArmorUpper","specialStatus":8},"Armor_228_Head":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":1515,"itemCreatingPrice":0,"itemSellingPrice":380,"profile":"ArmorHead","specialStatus":8},"Armor_228_Lower":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":1515,"itemCreatingPrice":0,"itemSellingPrice":380,"profile":"ArmorLower","specialStatus":8},"Armor_228_Upper":{"armorDefenceAddLevel":12,"armorEffectEffectType":"AttackUp","armorStarNum":4,"itemBuyingPrice":1515,"itemCreatingPrice":0,"itemSellingPrice":380,"profile":"ArmorUpper","specialStatus":8},"Armor_229_Head":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":2215,"itemCreatingPrice":0,"itemSellingPrice":555,"profile":"ArmorHead","specialStatus":8},"Armor_229_Lower":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":2215,"itemCreatingPrice":0,"itemSellingPrice":555,"profile":"ArmorLower","specialStatus":8},"Armor_229_Upper":{"armorDefenceAddLevel":20,"armorEffectEffectType":"AttackUp","armorStarNum":5,"itemBuyingPrice":2215,"itemCreatingPrice":0,"itemSellingPrice":555,"profile":"ArmorUpper","specialStatus":8},"Armor_230_Head":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorHead"},"Armor_230_Lower":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorLower"},"Armor_230_Upper":{"armorDefenceAddLevel":3,"armorStarNum":1,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":125,"profile":"ArmorUpper"},"Armor_231_Head":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":255,"profile":"ArmorHead"},"Armor_231_Lower":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":255,"profile":"ArmorLower"},"Armor_231_Upper":{"armorDefenceAddLevel":5,"armorStarNum":2,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":255,"profile":"ArmorUpper"},"Armor_232_Head":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":485,"profile":"ArmorHead"},"Armor_232_Lower":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":485,"profile":"ArmorLower"},"Armor_232_Upper":{"armorDefenceAddLevel":8,"armorStarNum":3,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":485,"profile":"ArmorUpper"},"Armor_233_Head":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorHead"},"Armor_233_Lower":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorLower"},"Armor_233_Upper":{"armorDefenceAddLevel":12,"armorStarNum":4,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":825,"profile":"ArmorUpper"},"Armor_234_Head":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1425,"profile":"ArmorHead"},"Armor_234_Lower":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1425,"profile":"ArmorLower"},"Armor_234_Upper":{"armorDefenceAddLevel":20,"armorStarNum":5,"itemBuyingPrice":60,"itemCreatingPrice":0,"itemSellingPrice":1425,"profile":"ArmorUpper"},"ArrowRainChild":{"attackPower":16,"profile":"Bullet"},"AssassinIronBall":{"attackPower":16,"profile":"Bullet"},"AssassinRockBall":{"attackPower":12,"profile":"Bullet"},"BeamosBeam":{"attackPower":12,"profile":"LineBeam"},"BeeHome":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":10,"profile":"CapturedActor"},"BombArrow_A":{"attackPower":40,"canStack":true,"cannotSell":true,"itemBuyingPrice":50,"itemSellingPrice":1,"profile":"Bullet"},"BrightArrow":{"attackPower":100,"cannotSell":true,"itemSellingPrice":1,"profile":"Bullet"},"BrightArrowTP":{"attackPower":100,"cannotSell":true,"itemSellingPrice":1,"profile":"Bullet"},"BrokenSnowBall":{"attackPower":1,"profile":"MapDynamicActive"},"CurseGanonBeam":{"attackPower":40,"profile":"Beam"},"DLC_RockBall":{"attackPower":12,"profile":"MapDynamicActive"},"DLC_WallSpike132":{"attackPower":4,"profile":"MapConstActive"},"DLC_WallSpikeMovableBox_A":{"attackPower":4,"profile":"MapDynamicActive"},"DLC_WallSpikeMovableBox_B":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_DLC_IbutsuEXD_FirePillar_A_01":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_DLC_IbutsuEXD_FirePillar_A_02":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_DLC_IbutsuExD_WallSpike_A_01":{"attackPower":4,"profile":"MapConstActive"},"DgnObj_DLC_IbutsuEx_C_Propeller_A_01":{"attackPower":5,"profile":"MapDynamicActive"},"DgnObj_DLC_IbutsuShaft_A_05":{"attackPower":5,"profile":"MapDynamicActive"},"DgnObj_DLC_WallSpikeMovable":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_DLC_Weapon_Sword_502":{"attackPower":1,"attackRange":1.6,"generalLife":40,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"DgnObj_FirePillar":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_B":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C_01":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C_02":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C_03":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C_04":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FirePillar_C_Physics":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_FloorSpike_A_01":{"attackPower":4,"profile":"MapConstActive"},"DgnObj_SliderSpike_A":{"attackPower":4,"profile":"MapDynamicActive"},"DgnObj_SpikeBall_028":{"attackPower":12,"profile":"MapDynamicActive"},"DgnObj_SpikeBall_051":{"attackPower":12,"profile":"MapDynamicActive"},"DgnObj_SpikeBall_A":{"attackPower":12,"profile":"MapDynamicActive"},"DgnObj_SpikeBall_B":{"attackPower":12,"profile":"MapDynamicActive"},"DgnObj_SpikeBall_NoHitRope":{"attackPower":12,"profile":"MapDynamicActive"},"DgnObj_WallSpike_067":{"attackPower":4,"profile":"MapConstActive"},"DgnObj_WallSpike_067_None":{"attackPower":4,"profile":"MapConstActive"},"DgnObj_WallSpike_B_01":{"attackPower":4,"profile":"MapConstActive"},"Dm_GameROMMotorcycle":{"attackPower":5,"attackRange":1.0,"generalLife":1,"profile":"DemoNPC"},"DragonFlameBall":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"DragonIceBall":{"attackPower":50,"attackRange":30.0,"profile":"Bullet"},"DragonThunderBall":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"ElectricArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"ElectricWaterBall":{"attackPower":40,"profile":"Bullet"},"Enemy_Assassin_Azito_Middle":{"attackPower":10,"attackRange":20.0,"generalLife":600,"profile":"Enemy"},"Enemy_Assassin_Azito_Middle_DLC2":{"attackPower":10,"attackRange":20.0,"generalLife":600,"profile":"Enemy"},"Enemy_Assassin_Middle":{"attackPower":10,"attackRange":20.0,"generalLife":400,"profile":"Enemy"},"Enemy_Assassin_Middle_Quest":{"attackPower":10,"attackRange":20.0,"generalLife":400,"profile":"Enemy"},"Enemy_Bokoblin_Bone_Junior":{"attackPower":4,"attackRange":1.0,"generalLife":1,"profile":"Enemy"},"Enemy_Bokoblin_Bone_Junior_AllDay":{"attackPower":4,"attackRange":1.0,"generalLife":1,"profile":"Enemy"},"Enemy_Bokoblin_Guard_Junior_Ambush":{"attackPower":4,"attackRange":1.0,"generalLife":13,"profile":"Enemy"},"Enemy_Bokoblin_Guard_Junior_TreeHouseTop":{"attackPower":4,"attackRange":1.0,"generalLife":13,"profile":"Enemy"},"Enemy_Bokoblin_Junior":{"attackPower":4,"attackRange":1.0,"generalLife":13,"profile":"Enemy"},"Enemy_Chuchu_Electric_Junior":{"attackPower":2,"attackRange":0.5,"generalLife":12,"profile":"GelEnemy"},"Enemy_Chuchu_Electric_Middle":{"attackPower":2,"attackRange":0.5,"generalLife":20,"profile":"GelEnemy"},"Enemy_Chuchu_Electric_Senior":{"attackPower":2,"attackRange":0.5,"generalLife":48,"profile":"GelEnemy"},"Enemy_Chuchu_Fire_Junior":{"attackPower":2,"attackRange":0.5,"generalLife":12,"profile":"GelEnemy"},"Enemy_Chuchu_Fire_Middle":{"attackPower":2,"attackRange":0.5,"generalLife":20,"profile":"GelEnemy"},"Enemy_Chuchu_Fire_Senior":{"attackPower":2,"attackRange":0.5,"generalLife":48,"profile":"GelEnemy"},"Enemy_Chuchu_Ice_Junior":{"attackPower":2,"attackRange":0.5,"generalLife":12,"profile":"GelEnemy"},"Enemy_Chuchu_Ice_Middle":{"attackPower":2,"attackRange":0.5,"generalLife":20,"profile":"GelEnemy"},"Enemy_Chuchu_Ice_Senior":{"attackPower":2,"attackRange":0.5,"generalLife":48,"profile":"GelEnemy"},"Enemy_Chuchu_Junior":{"attackPower":2,"attackRange":0.5,"generalLife":3,"profile":"GelEnemy"},"Enemy_Chuchu_Middle":{"attackPower":2,"attackRange":0.5,"generalLife":20,"profile":"GelEnemy"},"Enemy_Chuchu_Senior":{"attackPower":2,"attackRange":0.5,"generalLife":48,"profile":"GelEnemy"},"Enemy_Ganon":{"attackPower":60,"attackRange":100.0,"generalLife":8000,"profile":"LastBoss"},"Enemy_Ganon_Lsword_Weapon":{"attackPower":1,"attackRange":1.6,"generalLife":35,"profile":"WeaponLargeSword"},"Enemy_Ganon_Sword_Weapon_FL":{"attackPower":1,"attackRange":1.6,"generalLife":35,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Enemy_Ganon_Sword_Weapon_FR":{"attackPower":1,"attackRange":1.6,"generalLife":35,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Enemy_Ganon_Sword_Weapon_MR":{"attackPower":1,"attackRange":1.6,"generalLife":35,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Enemy_Giant_Bone":{"attackPower":60,"attackRange":7.0,"generalLife":1000,"profile":"GiantEnemy"},"Enemy_Giant_Bone_AllDay":{"attackPower":60,"attackRange":7.0,"generalLife":1000,"profile":"GiantEnemy"},"Enemy_Giant_Bone_Arm_L":{"attackPower":16,"profile":"Bullet"},"Enemy_Giant_Bone_Chin":{"attackPower":12,"profile":"Bullet"},"Enemy_Giant_Bone_Rib":{"attackPower":12,"profile":"Bullet"},"Enemy_Giant_Junior":{"attackPower":24,"attackRange":7.0,"generalLife":600,"profile":"GiantEnemy"},"Enemy_Giant_Middle":{"attackPower":48,"attackRange":7.0,"generalLife":800,"profile":"GiantEnemy"},"Enemy_Giant_Senior":{"attackPower":72,"attackRange":7.0,"generalLife":1000,"profile":"GiantEnemy"},"Enemy_Golem_Fire":{"attackPower":10,"attackRange":10.0,"generalLife":800,"profile":"GiantEnemy"},"Enemy_Golem_Fire_Lower_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Fire_Lower_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Fire_R":{"attackPower":10,"attackRange":10.0,"generalLife":1600,"profile":"GiantEnemy"},"Enemy_Golem_Fire_R_Lower_Arm_L":{"attackPower":60,"profile":"Bullet"},"Enemy_Golem_Fire_R_Lower_Arm_R":{"attackPower":60,"profile":"Bullet"},"Enemy_Golem_Fire_R_Upper_Arm_L":{"attackPower":60,"profile":"Bullet"},"Enemy_Golem_Fire_R_Upper_Arm_R":{"attackPower":60,"profile":"Bullet"},"Enemy_Golem_Fire_Upper_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Fire_Upper_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Ice":{"attackPower":10,"attackRange":10.0,"generalLife":800,"profile":"GiantEnemy"},"Enemy_Golem_Ice_Lower_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Ice_Lower_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Ice_Upper_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Ice_Upper_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Junior":{"attackPower":10,"attackRange":10.0,"generalLife":300,"profile":"GiantEnemy"},"Enemy_Golem_Little":{"attackPower":10,"attackRange":1.5,"generalLife":20,"profile":"Enemy"},"Enemy_Golem_Little_Fire":{"attackPower":10,"attackRange":1.5,"generalLife":20,"profile":"Enemy"},"Enemy_Golem_Little_Ice":{"attackPower":10,"attackRange":1.5,"generalLife":20,"profile":"Enemy"},"Enemy_Golem_Lower_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Lower_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Middle":{"attackPower":10,"attackRange":10.0,"generalLife":600,"profile":"GiantEnemy"},"Enemy_Golem_Senior":{"attackPower":10,"attackRange":10.0,"generalLife":900,"profile":"GiantEnemy"},"Enemy_Golem_Upper_Arm_L":{"attackPower":8,"profile":"Bullet"},"Enemy_Golem_Upper_Arm_R":{"attackPower":8,"profile":"Bullet"},"Enemy_Lynel_Junior":{"attackPower":15,"attackRange":5.0,"generalLife":2000,"profile":"Enemy"},"Enemy_Lynel_Junior_Mountain":{"attackPower":15,"attackRange":5.0,"generalLife":2000,"profile":"Enemy"},"Enemy_Octarock":{"attackPower":10,"attackRange":35.0,"generalLife":8,"profile":"Enemy"},"Enemy_Octarock_Desert":{"attackPower":10,"attackRange":35.0,"generalLife":8,"profile":"Enemy"},"Enemy_Octarock_Forest":{"attackPower":10,"attackRange":35.0,"generalLife":8,"profile":"Enemy"},"Enemy_Octarock_Snow":{"attackPower":10,"attackRange":35.0,"generalLife":8,"profile":"Enemy"},"Enemy_Octarock_Stone":{"attackPower":10,"attackRange":35.0,"generalLife":8,"profile":"Enemy"},"Enemy_SiteBoss_Lsword_Weapon":{"attackPower":1,"attackRange":1.6,"generalLife":35,"profile":"WeaponLargeSword"},"Enemy_SiteBoss_Spear_Weapon":{"attackPower":1,"attackRange":3.0,"profile":"WeaponSpear"},"Enemy_SiteBoss_Sword_Weapon":{"attackPower":1,"attackRange":1.6,"generalLife":35,"profile":"WeaponSmallSword"},"Explode":{"attackPower":10,"profile":"Bullet"},"FireArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"FireRodLv1Fire":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"FireRodLv2Fire":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"FireRodLv2FireChild":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"FldObj_GoronCannonBall_A_01":{"attackPower":1000,"profile":"MapDynamicActive"},"FldObj_GoronCannonBall_YunBo":{"attackPower":1000,"profile":"MapDynamicActive"},"FldObj_VolcanicBomb_A_01":{"attackPower":20,"profile":"MapDynamicActive"},"FldObj_VolcanicBomb_Field":{"attackPower":20,"profile":"MapDynamicActive"},"GaleArrow":{"attackPower":24,"profile":"Bullet"},"GameROMMotorcycle":{"attackPower":5,"attackRange":1.0,"generalLife":1,"profile":"Motorcycle"},"GameRomHorse":{"attackPower":5,"attackRange":1.0,"generalLife":220,"profile":"Horse"},"GameRomHorse00L":{"attackPower":10,"attackRange":1.0,"generalLife":300,"profile":"Horse"},"GameRomHorse00S":{"attackPower":5,"attackRange":1.0,"generalLife":120,"profile":"Horse"},"GameRomHorse01":{"attackPower":5,"attackRange":1.0,"generalLife":130,"profile":"Horse"},"GameRomHorse02":{"attackPower":5,"attackRange":1.0,"generalLife":130,"profile":"Horse"},"GameRomHorse03":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse04":{"attackPower":5,"attackRange":1.0,"generalLife":130,"profile":"Horse"},"GameRomHorse05":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse06":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse07":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse08":{"attackPower":5,"attackRange":1.0,"generalLife":160,"profile":"Horse"},"GameRomHorse09":{"attackPower":5,"attackRange":1.0,"generalLife":240,"profile":"Horse"},"GameRomHorse10":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse11":{"attackPower":5,"attackRange":1.0,"generalLife":130,"profile":"Horse"},"GameRomHorse12":{"attackPower":5,"attackRange":1.0,"generalLife":250,"profile":"Horse"},"GameRomHorse13":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse14":{"attackPower":5,"attackRange":1.0,"generalLife":80,"profile":"Horse"},"GameRomHorse15":{"attackPower":5,"attackRange":1.0,"generalLife":240,"profile":"Horse"},"GameRomHorse16":{"attackPower":5,"attackRange":1.0,"generalLife":150,"profile":"Horse"},"GameRomHorse17":{"attackPower":5,"attackRange":1.0,"generalLife":110,"profile":"Horse"},"GameRomHorse18":{"attackPower":5,"attackRange":1.0,"generalLife":110,"profile":"Horse"},"GameRomHorse19":{"attackPower":5,"attackRange":1.0,"generalLife":300,"profile":"Horse"},"GameRomHorse20":{"attackPower":5,"attackRange":1.0,"generalLife":220,"profile":"Horse"},"GameRomHorse21":{"attackPower":5,"attackRange":1.0,"generalLife":150,"profile":"Horse"},"GameRomHorse22":{"attackPower":5,"attackRange":1.0,"generalLife":150,"profile":"Horse"},"GameRomHorse23":{"attackPower":5,"attackRange":1.0,"profile":"Horse"},"GameRomHorseBone":{"attackPower":5,"attackRange":1.0,"profile":"Horse"},"GameRomHorseBone_AllDay":{"attackPower":5,"attackRange":1.0,"profile":"Horse"},"GameRomHorseEpona":{"attackPower":5,"attackRange":1.0,"generalLife":220,"profile":"Horse"},"GameRomHorseNushi":{"attackPower":5,"attackRange":1.0,"profile":"Horse"},"GameRomHorseReins_01":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseReins_02":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseReins_03":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseReins_04":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseReins_05":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseReins_10":{"cannotSell":true,"profile":"HorseReins"},"GameRomHorseSaddle_01":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseSaddle_02":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseSaddle_03":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseSaddle_04":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseSaddle_05":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseSaddle_10":{"cannotSell":true,"profile":"HorseSaddle"},"GameRomHorseZelda":{"attackPower":5,"attackRange":1.0,"generalLife":220,"profile":"Horse"},"GanonBeam":{"attackPower":40,"profile":"Beam"},"GanonBeastBeam":{"attackPower":72,"profile":"LineBeam"},"GanonFlameBall":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"GanonIceBullet":{"attackPower":24,"profile":"Bullet"},"GanonNormalArrow":{"attackPower":16,"profile":"Bullet"},"GanonPillarOfFlame":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"GanonSeaOfFlame":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"GanonSpearForThrowing":{"attackPower":16,"profile":"Bullet"},"GanonThunder":{"attackPower":24,"profile":"Bullet"},"GanonTornado":{"attackPower":24,"profile":"Bullet"},"Get_TwnObj_DLC_MemorialPicture_A_01":{"cannotSell":true,"profile":"Item"},"Giant_Bomb_Weapon":{"attackPower":30,"profile":"Bullet"},"Giant_Rock_Weapon":{"attackPower":8,"profile":"Bullet"},"GuardianBeam":{"attackPower":52,"profile":"Beam"},"GuardianBeam_RemainsWind":{"attackPower":52,"profile":"Beam"},"GuardianMiniBeam":{"attackPower":1,"attackRange":100.0,"profile":"Beam"},"GuardianMiniBeam_Junior":{"attackPower":10,"attackRange":100.0,"profile":"Beam"},"GuardianMiniBeam_Middle":{"attackPower":15,"attackRange":100.0,"profile":"Beam"},"GuardianMiniBeam_Senior":{"attackPower":20,"attackRange":100.0,"profile":"Beam"},"GuardianMiniFinalBeam":{"attackPower":1,"profile":"Beam"},"GuardianMiniFinalBeam_Junior":{"attackPower":20,"profile":"Beam"},"GuardianMiniFinalBeam_Middle":{"attackPower":30,"profile":"Beam"},"GuardianMiniFinalBeam_Senior":{"attackPower":40,"profile":"Beam"},"GuardianMiniLineBeam":{"attackPower":1,"profile":"LineBeam"},"GuardianMiniLineBeam_Junior":{"attackPower":16,"profile":"LineBeam"},"GuardianMiniLineBeam_Middle":{"attackPower":24,"profile":"LineBeam"},"GuardianMiniLineBeam_Senior":{"attackPower":32,"profile":"LineBeam"},"IceArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"IceRodLv1Ice":{"attackPower":50,"attackRange":30.0,"profile":"Bullet"},"IceRodLv2Ice":{"attackPower":50,"attackRange":30.0,"profile":"Bullet"},"Item_Boiled_01":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"Item"},"Item_ChilledFish_01":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":14,"profile":"Item"},"Item_ChilledFish_02":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":18,"profile":"Item"},"Item_ChilledFish_03":{"canStack":true,"itemBuyingPrice":25,"itemSellingPrice":10,"profile":"Item"},"Item_ChilledFish_04":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":18,"profile":"Item"},"Item_ChilledFish_05":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":18,"profile":"Item"},"Item_ChilledFish_06":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":14,"profile":"Item"},"Item_ChilledFish_07":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":14,"profile":"Item"},"Item_ChilledFish_08":{"canStack":true,"itemBuyingPrice":25,"itemSellingPrice":10,"profile":"Item"},"Item_ChilledFish_09":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":18,"profile":"Item"},"Item_Chilled_01":{"canStack":true,"itemBuyingPrice":35,"itemSellingPrice":15,"profile":"Item"},"Item_Chilled_02":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":28,"profile":"Item"},"Item_Chilled_03":{"canStack":true,"itemBuyingPrice":150,"itemSellingPrice":40,"profile":"Item"},"Item_Chilled_04":{"canStack":true,"itemBuyingPrice":35,"itemSellingPrice":15,"profile":"Item"},"Item_Chilled_05":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":28,"profile":"Item"},"Item_Chilled_06":{"canStack":true,"itemBuyingPrice":150,"itemSellingPrice":40,"profile":"Item"},"Item_Cook_A_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_10":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_11":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_12":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_13":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_A_14":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_11":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_12":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_13":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_14":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_15":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_16":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_17":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_18":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_19":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_20":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_21":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_22":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_B_23":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_11":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_12":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_13":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_14":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_15":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_16":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_17":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_C_17_00":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_D_10":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_E_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_E_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_E_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_E_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_F_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_F_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_F_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_F_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_10":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_11":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_12":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_13":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_14":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_15":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_16":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_G_17":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_H_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_H_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_H_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_10":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_11":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_12":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_13":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_14":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_15":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_16":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_I_17":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_J_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_06":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_07":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_08":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_K_09":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_L_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_L_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_L_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_L_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_L_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_M_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_N_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_N_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_N_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_N_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_O_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_O_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_P_01":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_P_02":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_P_03":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_P_04":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Cook_P_05":{"itemSellingPrice":1,"profile":"CookResult"},"Item_Enemy_00":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":15,"profile":"Item"},"Item_Enemy_01":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":8,"itemStainColor":13,"profile":"Item"},"Item_Enemy_02":{"canStack":true,"itemBuyingPrice":80,"itemSellingPrice":20,"itemStainColor":6,"profile":"Item"},"Item_Enemy_03":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":15,"profile":"Item"},"Item_Enemy_04":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":15,"profile":"Item"},"Item_Enemy_05":{"canStack":true,"itemBuyingPrice":112,"itemSellingPrice":28,"itemStainColor":7,"profile":"Item"},"Item_Enemy_06":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":15,"profile":"Item"},"Item_Enemy_07":{"canStack":true,"itemBuyingPrice":45,"itemSellingPrice":12,"itemStainColor":15,"profile":"Item"},"Item_Enemy_08":{"canStack":true,"itemBuyingPrice":100,"itemSellingPrice":25,"itemStainColor":8,"profile":"Item"},"Item_Enemy_12":{"canStack":true,"itemBuyingPrice":160,"itemSellingPrice":40,"itemStainColor":4,"profile":"Item"},"Item_Enemy_13":{"canStack":true,"itemBuyingPrice":200,"itemSellingPrice":50,"itemStainColor":5,"profile":"Item"},"Item_Enemy_14":{"canStack":true,"itemBuyingPrice":800,"itemSellingPrice":200,"itemStainColor":12,"profile":"Item"},"Item_Enemy_15":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":2,"profile":"Item"},"Item_Enemy_16":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":3,"profile":"Item"},"Item_Enemy_17":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":4,"profile":"Item"},"Item_Enemy_18":{"canStack":true,"itemBuyingPrice":8,"itemSellingPrice":2,"itemStainColor":15,"profile":"Item"},"Item_Enemy_19":{"canStack":true,"itemBuyingPrice":80,"itemSellingPrice":20,"itemStainColor":10,"profile":"Item"},"Item_Enemy_20":{"canStack":true,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":8,"profile":"Item"},"Item_Enemy_21":{"canStack":true,"itemBuyingPrice":100,"itemSellingPrice":25,"itemStainColor":3,"profile":"Item"},"Item_Enemy_24":{"canStack":true,"itemBuyingPrice":120,"itemSellingPrice":30,"itemStainColor":14,"profile":"Item"},"Item_Enemy_25":{"canStack":true,"itemBuyingPrice":440,"itemSellingPrice":110,"itemStainColor":7,"profile":"Item"},"Item_Enemy_26":{"canStack":true,"itemBuyingPrice":120,"itemSellingPrice":30,"itemStainColor":15,"profile":"Item"},"Item_Enemy_27":{"canStack":true,"itemBuyingPrice":48,"itemSellingPrice":12,"itemStainColor":15,"profile":"Item"},"Item_Enemy_28":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":15,"profile":"Item"},"Item_Enemy_29":{"canStack":true,"itemBuyingPrice":160,"itemSellingPrice":40,"itemStainColor":15,"profile":"Item"},"Item_Enemy_30":{"canStack":true,"generalLife":1,"itemBuyingPrice":320,"itemSellingPrice":80,"itemStainColor":15,"profile":"Item"},"Item_Enemy_31":{"canStack":true,"generalLife":1,"itemBuyingPrice":800,"itemSellingPrice":200,"itemStainColor":15,"profile":"Item"},"Item_Enemy_32":{"canStack":true,"itemBuyingPrice":80,"itemSellingPrice":20,"itemStainColor":14,"profile":"Item"},"Item_Enemy_33":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"itemStainColor":14,"profile":"Item"},"Item_Enemy_34":{"canStack":true,"itemBuyingPrice":320,"itemSellingPrice":80,"itemStainColor":3,"profile":"Item"},"Item_Enemy_38":{"canStack":true,"itemBuyingPrice":600,"itemSellingPrice":150,"itemStainColor":12,"profile":"Item"},"Item_Enemy_39":{"canStack":true,"itemBuyingPrice":720,"itemSellingPrice":180,"itemStainColor":12,"profile":"Item"},"Item_Enemy_40":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":8,"profile":"Item"},"Item_Enemy_41":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"itemStainColor":2,"profile":"Item"},"Item_Enemy_42":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"itemStainColor":1,"profile":"Item"},"Item_Enemy_43":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"itemStainColor":3,"profile":"Item"},"Item_Enemy_44":{"canStack":true,"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":2,"profile":"Item"},"Item_Enemy_45":{"canStack":true,"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":3,"profile":"Item"},"Item_Enemy_46":{"canStack":true,"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":1,"profile":"Item"},"Item_Enemy_47":{"canStack":true,"itemBuyingPrice":1000,"itemSellingPrice":250,"itemStainColor":12,"profile":"Item"},"Item_Enemy_48":{"canStack":true,"itemBuyingPrice":1200,"itemSellingPrice":300,"itemStainColor":12,"profile":"Item"},"Item_Enemy_49":{"canStack":true,"itemBuyingPrice":600,"itemSellingPrice":150,"itemStainColor":8,"profile":"Item"},"Item_Enemy_50":{"canStack":true,"itemBuyingPrice":720,"itemSellingPrice":180,"itemStainColor":8,"profile":"Item"},"Item_Enemy_51":{"canStack":true,"itemBuyingPrice":1000,"itemSellingPrice":250,"itemStainColor":8,"profile":"Item"},"Item_Enemy_52":{"canStack":true,"itemBuyingPrice":1200,"itemSellingPrice":300,"itemStainColor":8,"profile":"Item"},"Item_Enemy_53":{"canStack":true,"itemBuyingPrice":600,"itemSellingPrice":150,"itemStainColor":13,"profile":"Item"},"Item_Enemy_54":{"canStack":true,"itemBuyingPrice":720,"itemSellingPrice":180,"itemStainColor":13,"profile":"Item"},"Item_Enemy_55":{"canStack":true,"itemBuyingPrice":1000,"itemSellingPrice":250,"itemStainColor":13,"profile":"Item"},"Item_Enemy_56":{"canStack":true,"itemBuyingPrice":1200,"itemSellingPrice":300,"itemStainColor":13,"profile":"Item"},"Item_Enemy_57":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":6,"profile":"Item"},"Item_Enemy_Put_57":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":6,"profile":"Item"},"Item_FishGet_A":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"Item"},"Item_FishGet_B":{"canStack":true,"generalLife":1,"itemBuyingPrice":72,"itemSellingPrice":18,"profile":"Item"},"Item_FishGet_C":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"Item"},"Item_FishGet_D":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"Item"},"Item_FishGet_E":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_F":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_G":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_H":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_J":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"Item"},"Item_FishGet_K":{"canStack":true,"generalLife":1,"itemBuyingPrice":60,"itemSellingPrice":15,"profile":"Item"},"Item_FishGet_L":{"canStack":true,"generalLife":1,"itemBuyingPrice":72,"itemSellingPrice":18,"profile":"Item"},"Item_FishGet_M":{"canStack":true,"generalLife":1,"itemBuyingPrice":24,"itemSellingPrice":6,"profile":"Item"},"Item_FishGet_X":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_FishGet_Z":{"canStack":true,"generalLife":1,"itemBuyingPrice":80,"itemSellingPrice":20,"profile":"Item"},"Item_Fruit_A":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":2,"profile":"Item"},"Item_Fruit_B":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":11,"profile":"Item"},"Item_Fruit_C":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":10,"profile":"Item"},"Item_Fruit_D":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":13,"profile":"Item"},"Item_Fruit_E":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":7,"profile":"Item"},"Item_Fruit_F":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":7,"profile":"Item"},"Item_Fruit_G":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":13,"profile":"Item"},"Item_Fruit_H":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":3,"profile":"Item"},"Item_Fruit_I":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":2,"profile":"Item"},"Item_Fruit_J":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":10,"profile":"Item"},"Item_Fruit_K":{"canStack":true,"itemBuyingPrice":8,"itemSellingPrice":2,"itemStainColor":14,"profile":"Item"},"Item_Fruit_L":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":12,"profile":"Item"},"Item_InsectGet_K":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"Item"},"Item_InsectGet_O":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"Item"},"Item_InsectGet_Z":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"Item"},"Item_Material_01":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":7,"profile":"Item"},"Item_Material_02":{"canStack":true,"generalLife":1,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":12,"profile":"Item"},"Item_Material_03":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":4,"profile":"Item"},"Item_Material_04":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":3,"profile":"Item"},"Item_Material_05":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":4,"profile":"Item"},"Item_Material_05_00":{"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":4,"profile":"Item"},"Item_Material_06":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":13,"profile":"Item"},"Item_Material_07":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":13,"profile":"Item"},"Item_Material_08":{"canStack":true,"generalLife":1,"itemBuyingPrice":10,"itemSellingPrice":3,"itemStainColor":6,"profile":"Item"},"Item_Meat_01":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"Item"},"Item_Meat_02":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"profile":"Item"},"Item_Meat_06":{"canStack":true,"itemBuyingPrice":32,"itemSellingPrice":8,"profile":"Item"},"Item_Meat_07":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"profile":"Item"},"Item_Meat_11":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"profile":"Item"},"Item_Meat_12":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"profile":"Item"},"Item_MushroomGet_D":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":6,"profile":"Item"},"Item_Mushroom_A":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":7,"profile":"Item"},"Item_Mushroom_B":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":1,"profile":"Item"},"Item_Mushroom_C":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":2,"profile":"Item"},"Item_Mushroom_D":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":6,"profile":"Item"},"Item_Mushroom_E":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":2,"profile":"Item"},"Item_Mushroom_F":{"canStack":true,"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":5,"profile":"Item"},"Item_Mushroom_F_00":{"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":5,"profile":"Item"},"Item_Mushroom_H":{"canStack":true,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":3,"profile":"Item"},"Item_Mushroom_J":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":8,"profile":"Item"},"Item_Mushroom_L":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":12,"profile":"Item"},"Item_Mushroom_M":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":14,"profile":"Item"},"Item_Mushroom_N":{"canStack":true,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":5,"profile":"Item"},"Item_Mushroom_N_00":{"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":5,"profile":"Item"},"Item_Mushroom_O":{"canStack":true,"itemBuyingPrice":24,"itemSellingPrice":6,"itemStainColor":10,"profile":"Item"},"Item_Ore_A":{"canStack":true,"itemBuyingPrice":2000,"itemSellingPrice":500,"itemStainColor":4,"profile":"Item"},"Item_Ore_A_00":{"itemBuyingPrice":2000,"itemSellingPrice":500,"itemStainColor":4,"profile":"Item"},"Item_Ore_B":{"canStack":true,"itemBuyingPrice":840,"itemSellingPrice":210,"itemStainColor":2,"profile":"Item"},"Item_Ore_C":{"canStack":true,"itemBuyingPrice":1040,"itemSellingPrice":260,"itemStainColor":1,"profile":"Item"},"Item_Ore_D":{"canStack":true,"itemBuyingPrice":720,"itemSellingPrice":180,"itemStainColor":3,"profile":"Item"},"Item_Ore_E":{"canStack":true,"itemBuyingPrice":240,"itemSellingPrice":60,"itemStainColor":13,"profile":"Item"},"Item_Ore_F":{"canStack":true,"itemBuyingPrice":120,"itemSellingPrice":30,"itemStainColor":10,"profile":"Item"},"Item_Ore_G":{"canStack":true,"itemBuyingPrice":280,"itemSellingPrice":70,"itemStainColor":9,"profile":"Item"},"Item_Ore_H":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":2,"itemStainColor":11,"profile":"Item"},"Item_Ore_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":5,"profile":"Item"},"Item_Ore_J":{"canStack":true,"itemBuyingPrice":1500,"itemSellingPrice":300,"itemStainColor":4,"profile":"Item"},"Item_PlantGet_A":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":7,"profile":"Item"},"Item_PlantGet_B":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"itemStainColor":11,"profile":"Item"},"Item_PlantGet_C":{"canStack":true,"generalLife":1,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":11,"profile":"Item"},"Item_PlantGet_E":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":8,"profile":"Item"},"Item_PlantGet_F":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":10,"profile":"Item"},"Item_PlantGet_G":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":10,"profile":"Item"},"Item_PlantGet_H":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":6,"profile":"Item"},"Item_PlantGet_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":1,"profile":"Item"},"Item_PlantGet_J":{"canStack":true,"generalLife":1,"itemBuyingPrice":30,"itemSellingPrice":10,"itemStainColor":4,"profile":"Item"},"Item_PlantGet_L":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":13,"profile":"Item"},"Item_PlantGet_M":{"canStack":true,"generalLife":1,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":10,"profile":"Item"},"Item_PlantGet_O":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":6,"profile":"Item"},"Item_PlantGet_Q":{"canStack":true,"generalLife":1,"itemBuyingPrice":120,"itemSellingPrice":30,"itemStainColor":13,"profile":"Item"},"Item_Plant_A":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":7,"profile":"Item"},"Item_Plant_B":{"canStack":true,"generalLife":1,"itemBuyingPrice":32,"itemSellingPrice":8,"itemStainColor":11,"profile":"Item"},"Item_Plant_C":{"canStack":true,"generalLife":1,"itemBuyingPrice":60,"itemSellingPrice":15,"itemStainColor":11,"profile":"Item"},"Item_Plant_E":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":8,"profile":"Item"},"Item_Plant_F":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":10,"profile":"Item"},"Item_Plant_G":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":10,"profile":"Item"},"Item_Plant_H":{"canStack":true,"generalLife":1,"itemBuyingPrice":20,"itemSellingPrice":5,"itemStainColor":6,"profile":"Item"},"Item_Plant_I":{"canStack":true,"generalLife":1,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":1,"profile":"Item"},"Item_Plant_J":{"canStack":true,"generalLife":1,"itemBuyingPrice":80,"itemSellingPrice":40,"itemStainColor":4,"profile":"Item"},"Item_Plant_L":{"canStack":true,"generalLife":1,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":13,"profile":"Item"},"Item_Plant_M":{"canStack":true,"generalLife":1,"itemBuyingPrice":16,"itemSellingPrice":4,"itemStainColor":10,"profile":"Item"},"Item_Plant_O":{"canStack":true,"generalLife":1,"itemBuyingPrice":40,"itemSellingPrice":10,"itemStainColor":6,"profile":"Item"},"Item_Plant_Q":{"canStack":true,"generalLife":1,"itemBuyingPrice":120,"itemSellingPrice":30,"itemStainColor":13,"profile":"Item"},"Item_RoastFish_01":{"canStack":true,"itemBuyingPrice":23,"itemSellingPrice":9,"profile":"Item"},"Item_RoastFish_02":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_RoastFish_03":{"canStack":true,"itemBuyingPrice":23,"itemSellingPrice":9,"profile":"Item"},"Item_RoastFish_04":{"canStack":true,"itemBuyingPrice":38,"itemSellingPrice":15,"profile":"Item"},"Item_RoastFish_07":{"canStack":true,"itemBuyingPrice":38,"itemSellingPrice":15,"profile":"Item"},"Item_RoastFish_09":{"canStack":true,"itemBuyingPrice":38,"itemSellingPrice":15,"profile":"Item"},"Item_RoastFish_11":{"canStack":true,"itemBuyingPrice":38,"itemSellingPrice":15,"profile":"Item"},"Item_RoastFish_13":{"canStack":true,"itemBuyingPrice":23,"itemSellingPrice":9,"profile":"Item"},"Item_RoastFish_15":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_Roast_01":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_Roast_02":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_Roast_03":{"canStack":true,"itemBuyingPrice":8,"itemSellingPrice":3,"profile":"Item"},"Item_Roast_04":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_05":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_06":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":3,"itemStainColor":2,"profile":"Item"},"Item_Roast_07":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_08":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_09":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_Roast_10":{"canStack":true,"itemBuyingPrice":15,"itemSellingPrice":6,"profile":"Item"},"Item_Roast_11":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_12":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_13":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_15":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_16":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_18":{"canStack":true,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"Item"},"Item_Roast_19":{"canStack":true,"itemBuyingPrice":58,"itemSellingPrice":24,"profile":"Item"},"Item_Roast_24":{"canStack":true,"itemBuyingPrice":15,"itemSellingPrice":6,"profile":"Item"},"Item_Roast_27":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_28":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":8,"profile":"Item"},"Item_Roast_31":{"canStack":true,"itemBuyingPrice":15,"itemSellingPrice":6,"profile":"Item"},"Item_Roast_32":{"canStack":true,"itemBuyingPrice":15,"itemSellingPrice":6,"profile":"Item"},"Item_Roast_33":{"canStack":true,"itemBuyingPrice":15,"itemSellingPrice":6,"profile":"Item"},"Item_Roast_36":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_37":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_38":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_39":{"canStack":true,"itemBuyingPrice":8,"itemSellingPrice":3,"profile":"Item"},"Item_Roast_40":{"canStack":true,"itemBuyingPrice":58,"itemSellingPrice":24,"profile":"Item"},"Item_Roast_41":{"canStack":true,"itemBuyingPrice":28,"itemSellingPrice":24,"profile":"Item"},"Item_Roast_45":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"profile":"Item"},"Item_Roast_46":{"canStack":true,"itemBuyingPrice":140,"itemSellingPrice":35,"profile":"Item"},"Item_Roast_48":{"canStack":true,"itemBuyingPrice":5,"itemSellingPrice":2,"profile":"Item"},"Item_Roast_49":{"canStack":true,"itemBuyingPrice":58,"itemSellingPrice":24,"profile":"Item"},"Item_Roast_50":{"canStack":true,"itemBuyingPrice":95,"itemSellingPrice":38,"profile":"Item"},"Item_Roast_51":{"canStack":true,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"Item"},"Item_Roast_52":{"canStack":true,"itemBuyingPrice":5,"itemSellingPrice":2,"profile":"Item"},"Item_Roast_53":{"canStack":true,"itemBuyingPrice":13,"itemSellingPrice":5,"profile":"Item"},"Kokko_Simple":{"attackPower":2,"profile":"MapDynamicActive"},"LastBossThunder":{"attackPower":24,"profile":"Bullet"},"LizalfosFlame":{"attackPower":24,"attackRange":10.0,"profile":"Bullet"},"Lizalfos_ElectricWaterBall":{"attackPower":40,"profile":"Bullet"},"Lizalfos_IceBall":{"attackRange":100.0,"profile":"Bullet"},"Lizalfos_Lava":{"attackRange":30.0,"profile":"Bullet"},"Lizalfos_Water":{"attackRange":30.0,"profile":"Bullet"},"LynelFlame":{"attackPower":1,"attackRange":5.0,"profile":"Bullet"},"NormalArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":5,"itemSellingPrice":1,"profile":"Bullet"},"Obj_AncientArrow_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":100,"itemCreatingPrice":90,"profile":"Item"},"Obj_AncientArrow_B_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":400,"itemCreatingPrice":400,"profile":"Item"},"Obj_AncientArrow_C_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":250,"itemCreatingPrice":250,"profile":"Item"},"Obj_Armor_115_Head":{"cannotSell":true,"profile":"Item"},"Obj_ArrowBundle_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"profile":"Item"},"Obj_ArrowBundle_A_02":{"canStack":true,"cannotSell":true,"itemBuyingPrice":35,"profile":"Item"},"Obj_ArrowBundle_A_10":{"canStack":true,"cannotSell":true,"itemBuyingPrice":35,"profile":"Item"},"Obj_ArrowNormal_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":5,"itemSellingPrice":1,"profile":"Item"},"Obj_BombArrow_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":50,"itemSellingPrice":1,"profile":"Item"},"Obj_BombArrow_A_02":{"canStack":true,"cannotSell":true,"itemBuyingPrice":200,"profile":"Item"},"Obj_BombArrow_A_03":{"canStack":true,"cannotSell":true,"itemBuyingPrice":350,"profile":"Item"},"Obj_BombArrow_A_04":{"canStack":true,"cannotSell":true,"itemBuyingPrice":600,"profile":"Item"},"Obj_Cushion":{"itemBuyingPrice":500,"itemCreatingPrice":500,"itemSellingPrice":500,"profile":"Item"},"Obj_DLC_HeroSeal_Gerudo":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSeal_Goron":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSeal_Rito":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSeal_Zora":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSoul_Gerudo":{"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSoul_Goron":{"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSoul_Rito":{"cannotSell":true,"profile":"Item"},"Obj_DLC_HeroSoul_Zora":{"cannotSell":true,"profile":"Item"},"Obj_DRStone_Get":{"cannotSell":true,"profile":"PlayerItem"},"Obj_DungeonClearSeal":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_ElectricArrow_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Item"},"Obj_ElectricArrow_A_02":{"canStack":true,"cannotSell":true,"itemBuyingPrice":140,"itemCreatingPrice":10,"profile":"Item"},"Obj_ElectricArrow_A_03":{"canStack":true,"cannotSell":true,"itemBuyingPrice":80,"itemCreatingPrice":10,"profile":"Item"},"Obj_ElectricArrow_B_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Item"},"Obj_FireArrow_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Item"},"Obj_FireArrow_A_02":{"canStack":true,"cannotSell":true,"itemBuyingPrice":140,"itemCreatingPrice":10,"itemSellingPrice":2,"profile":"Item"},"Obj_FireArrow_A_03":{"canStack":true,"cannotSell":true,"itemBuyingPrice":80,"itemCreatingPrice":10,"itemSellingPrice":2,"profile":"Item"},"Obj_FireWoodBundle":{"canStack":true,"itemBuyingPrice":12,"itemSellingPrice":2,"profile":"Item"},"Obj_Head_024":{"itemBuyingPrice":800,"itemCreatingPrice":800,"itemSellingPrice":800,"profile":"Item"},"Obj_Head_025":{"itemBuyingPrice":500,"itemCreatingPrice":500,"itemSellingPrice":500,"profile":"Item"},"Obj_Head_026":{"itemBuyingPrice":500,"itemCreatingPrice":500,"itemSellingPrice":500,"profile":"Item"},"Obj_Head_027":{"itemBuyingPrice":400,"itemCreatingPrice":400,"itemSellingPrice":400,"profile":"Item"},"Obj_Head_028":{"itemBuyingPrice":200,"itemCreatingPrice":200,"itemSellingPrice":200,"profile":"Item"},"Obj_Head_029":{"itemBuyingPrice":80,"itemCreatingPrice":80,"itemSellingPrice":80,"profile":"Item"},"Obj_HeroSoul_Gerudo":{"cannotSell":true,"profile":"Item"},"Obj_HeroSoul_Goron":{"cannotSell":true,"profile":"Item"},"Obj_HeroSoul_Rito":{"cannotSell":true,"profile":"Item"},"Obj_HeroSoul_Zora":{"cannotSell":true,"profile":"Item"},"Obj_IceArrow_A_01":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Item"},"Obj_IceArrow_A_02":{"canStack":true,"cannotSell":true,"itemBuyingPrice":140,"itemCreatingPrice":10,"profile":"Item"},"Obj_IceArrow_A_03":{"canStack":true,"cannotSell":true,"itemBuyingPrice":80,"itemCreatingPrice":10,"profile":"Item"},"Obj_KorokNuts":{"canStack":true,"cannotSell":true,"profile":"Item"},"Obj_Maracas":{"cannotSell":true,"profile":"Item"},"Obj_Photo_Animal":{"cannotSell":true,"itemBuyingPrice":100,"profile":"Item"},"Obj_Photo_BossEnemy":{"cannotSell":true,"itemBuyingPrice":500,"profile":"Item"},"Obj_Photo_Enemy":{"cannotSell":true,"itemBuyingPrice":100,"profile":"Item"},"Obj_Photo_Material":{"cannotSell":true,"itemBuyingPrice":100,"profile":"Item"},"Obj_Photo_Other":{"cannotSell":true,"itemBuyingPrice":100,"profile":"Item"},"Obj_Photo_Weapon":{"cannotSell":true,"itemBuyingPrice":100,"profile":"Item"},"Obj_ProofBook":{"cannotSell":true,"profile":"Item"},"Obj_ProofGiantKiller":{"cannotSell":true,"profile":"Item"},"Obj_ProofGolemKiller":{"cannotSell":true,"profile":"Item"},"Obj_ProofKorok":{"cannotSell":true,"profile":"Item"},"Obj_ProofSandwormKiller":{"cannotSell":true,"profile":"Item"},"Obj_WarpDLC":{"cannotSell":true,"profile":"Item"},"Octarock_Bullet":{"attackPower":2,"profile":"Bullet"},"Octarock_Bullet_L":{"attackPower":1,"profile":"Bullet"},"Octarock_SnowBullet":{"attackPower":2,"profile":"Bullet"},"PlayerBeam":{"attackPower":10,"profile":"Bullet"},"PlayerStole2":{"cannotSell":true,"profile":"PlayerItem"},"PriestBossThunder":{"attackPower":24,"profile":"Bullet"},"Priest_Boss_Beam":{"attackPower":40,"profile":"Beam"},"Priest_Boss_ElectricArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"Priest_Boss_FireArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"Priest_Boss_IceArrow":{"canStack":true,"cannotSell":true,"itemBuyingPrice":20,"itemSellingPrice":1,"profile":"Bullet"},"Priest_Boss_IronBall":{"attackPower":20,"profile":"MapDynamicActive"},"Priest_Boss_Weapon_Bow_029":{"attackPower":10,"attackRange":40.0,"bowIsLongRange":true,"cannotSell":true,"generalLife":45,"itemBuyingPrice":50,"itemSellingPrice":10,"profile":"WeaponBow"},"Priest_Boss_Weapon_Sword_015":{"attackPower":40,"attackRange":1.6,"cannotSell":true,"generalLife":32,"itemBuyingPrice":114,"itemSellingPrice":45,"profile":"WeaponSmallSword"},"RemainsElectric":{"attackPower":70,"profile":"Remains"},"RemainsElectricCannon":{"attackPower":60,"attackRange":100.0,"generalLife":2000,"profile":"Enemy"},"RemainsElectric_Far":{"attackPower":70,"profile":"Remains"},"RemainsWaterChaseBullet":{"attackPower":4,"profile":"Bullet"},"RemainsWaterExplodeBullet":{"attackPower":4,"profile":"Bullet"},"RemainsWind":{"attackPower":4,"profile":"Remains"},"RemainsWind_Barrier_A_01":{"attackPower":4,"profile":"MapDynamicActive"},"RemainsWind_Far":{"attackPower":4,"profile":"Remains"},"RockBall":{"attackPower":12,"profile":"MapDynamicActive"},"Rock_Moriblin":{"attackPower":1,"attackRange":5.0,"profile":"Bullet"},"Rock_Weapon":{"attackPower":1,"attackRange":5.0,"profile":"Bullet"},"SimpleBeam":{"attackPower":52,"profile":"Beam"},"SiteBossBigFlameBall":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossDrawingFlameTornado":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossFlameBall":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossGaleArrow":{"attackPower":24,"profile":"Bullet"},"SiteBossNormalArrow":{"attackPower":16,"profile":"Bullet"},"SiteBossPillarOfFlame":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossReflectArrow":{"attackPower":16,"profile":"Bullet"},"SiteBossSeaOfFlame":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossSeaOfFlameRotate":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"SiteBossSpearForThrowing":{"attackPower":16,"profile":"Bullet"},"SiteBossSpearIceBullet":{"attackPower":24,"profile":"Bullet"},"SiteBossTornado":{"attackPower":24,"profile":"Bullet"},"SiteBossWearFlame":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"ThunderRodLv1Thunder":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"ThunderRodLv2Thunder":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"ThunderRodLv2ThunderChild":{"attackPower":24,"attackRange":30.0,"profile":"Bullet"},"WallSpike":{"attackPower":4,"profile":"MapConstActive"},"WallSpikeTgt":{"attackPower":4,"profile":"MapConstActive"},"Weapon_Arrow_020":{"attackPower":40,"itemBuyingPrice":50,"itemSellingPrice":1,"profile":"Bullet"},"Weapon_Bow_001":{"attackPower":5,"attackRange":20.0,"cannotSell":true,"generalLife":22,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponBow"},"Weapon_Bow_002":{"attackPower":14,"attackRange":20.0,"cannotSell":true,"generalLife":36,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponBow"},"Weapon_Bow_003":{"attackPower":12,"attackRange":20.0,"bowLeadShotAng":13.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":20,"itemBuyingPrice":30,"itemSellingPrice":10,"profile":"WeaponBow"},"Weapon_Bow_004":{"attackPower":4,"attackRange":20.0,"cannotSell":true,"generalLife":16,"itemBuyingPrice":9,"itemSellingPrice":3,"profile":"WeaponBow"},"Weapon_Bow_006":{"attackPower":14,"attackRange":20.0,"cannotSell":true,"generalLife":25,"itemBuyingPrice":24,"itemSellingPrice":8,"profile":"WeaponBow"},"Weapon_Bow_009":{"attackPower":10,"attackRange":20.0,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":30,"itemBuyingPrice":54,"itemSellingPrice":18,"profile":"WeaponBow","specialStatus":27},"Weapon_Bow_011":{"attackPower":25,"attackRange":20.0,"bowLeadShotAng":13.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":35,"itemBuyingPrice":30,"itemSellingPrice":10,"profile":"WeaponBow"},"Weapon_Bow_013":{"attackPower":15,"attackRange":20.0,"bowArrowChargeRate":1.6,"bowArrowFirstSpeed":4.0,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":35,"itemBuyingPrice":30,"itemSellingPrice":7,"profile":"WeaponBow","specialStatus":27},"Weapon_Bow_014":{"attackPower":15,"attackRange":20.0,"bowArrowGravity":-7.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":65,"itemSellingPrice":16,"profile":"WeaponBow"},"Weapon_Bow_015":{"attackPower":14,"attackRange":40.0,"bowIsLongRange":true,"cannotSell":true,"generalLife":60,"itemBuyingPrice":85,"itemSellingPrice":21,"profile":"WeaponBow"},"Weapon_Bow_016":{"attackPower":9,"attackRange":40.0,"bowArrowChargeRate":1.3,"cannotSell":true,"generalLife":30,"itemBuyingPrice":40,"itemSellingPrice":10,"profile":"WeaponBow"},"Weapon_Bow_017":{"attackPower":20,"attackRange":40.0,"bowArrowChargeRate":1.6,"bowLeadShotAng":13.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":50,"itemBuyingPrice":190,"itemSellingPrice":48,"profile":"WeaponBow"},"Weapon_Bow_023":{"attackPower":44,"attackRange":40.0,"bowArrowChargeRate":0.7,"bowArrowGravity":-2.8,"bowArrowStabilitySpeed":4.0,"bowIsGuardPierce":true,"cannotSell":true,"generalLife":120,"itemBuyingPrice":20,"itemCreatingPrice":1000,"itemSellingPrice":5,"profile":"WeaponBow"},"Weapon_Bow_026":{"attackPower":20,"attackRange":20.0,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":35,"itemBuyingPrice":105,"itemSellingPrice":35,"profile":"WeaponBow","specialStatus":27},"Weapon_Bow_027":{"attackPower":24,"attackRange":20.0,"bowLeadShotAng":20.0,"bowLeadShotInterval":1,"bowLeadShotNum":5,"cannotSell":true,"generalLife":30,"itemBuyingPrice":50,"itemSellingPrice":15,"profile":"WeaponBow"},"Weapon_Bow_028":{"attackPower":28,"attackRange":40.0,"bowArrowChargeRate":1.8,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":60,"itemBuyingPrice":380,"itemSellingPrice":120,"profile":"WeaponBow","specialStatus":27},"Weapon_Bow_029":{"attackPower":10,"attackRange":40.0,"bowIsLongRange":true,"cannotSell":true,"generalLife":45,"itemBuyingPrice":50,"itemSellingPrice":10,"profile":"WeaponBow"},"Weapon_Bow_030":{"attackPower":36,"attackRange":20.0,"bowLeadShotAng":20.0,"bowLeadShotInterval":1,"bowLeadShotNum":5,"cannotSell":true,"generalLife":50,"itemBuyingPrice":50,"itemSellingPrice":16,"profile":"WeaponBow"},"Weapon_Bow_032":{"attackPower":32,"attackRange":20.0,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"cannotSell":true,"generalLife":45,"itemBuyingPrice":156,"itemSellingPrice":52,"profile":"WeaponBow","specialStatus":27},"Weapon_Bow_033":{"attackPower":50,"attackRange":30.0,"bowArrowChargeRate":1.5,"bowArrowFirstSpeed":8.0,"bowArrowReloadRate":0.8,"bowArrowStabilitySpeed":4.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":300,"itemSellingPrice":100,"profile":"WeaponBow"},"Weapon_Bow_035":{"attackPower":26,"attackRange":20.0,"cannotSell":true,"generalLife":48,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponBow"},"Weapon_Bow_036":{"attackPower":38,"attackRange":20.0,"cannotSell":true,"generalLife":60,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponBow"},"Weapon_Bow_038":{"attackPower":4,"attackRange":20.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponBow"},"Weapon_Bow_040":{"attackPower":14,"attackRange":40.0,"bowRapidFireNum":2,"cannotSell":true,"generalLife":18,"profile":"WeaponBow"},"Weapon_Bow_071":{"attackPower":100,"attackRange":500.0,"bowArrowFirstSpeed":7.0,"bowArrowGravity":-5.0,"bowArrowStabilitySpeed":5.0,"cannotSell":true,"profile":"WeaponBow"},"Weapon_Bow_072":{"attackPower":30,"attackRange":8000.0,"bowArrowFirstSpeed":7.0,"bowArrowGravity":-5.0,"bowArrowStabilitySpeed":5.0,"cannotSell":true,"profile":"WeaponBow"},"Weapon_Bow_080":{"attackPower":28,"attackRange":40.0,"bowArrowChargeRate":1.8,"bowLeadShotAng":3.0,"bowLeadShotInterval":1,"bowLeadShotNum":3,"generalLife":60,"itemBuyingPrice":380,"itemSellingPrice":120,"profile":"WeaponBow","specialStatus":27},"Weapon_Goron_Knuckle":{"attackPower":5,"attackRange":1.6,"profile":"WeaponSmallSword"},"Weapon_Lsword_001":{"attackPower":10,"attackRange":1.8,"cannotSell":true,"generalLife":20,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponLargeSword"},"Weapon_Lsword_002":{"attackPower":20,"attackRange":1.8,"cannotSell":true,"generalLife":25,"itemBuyingPrice":75,"itemSellingPrice":18,"profile":"WeaponLargeSword"},"Weapon_Lsword_003":{"attackPower":38,"attackRange":1.8,"cannotSell":true,"generalLife":30,"itemBuyingPrice":165,"itemSellingPrice":42,"profile":"WeaponLargeSword"},"Weapon_Lsword_004":{"attackPower":6,"attackRange":1.8,"cannotSell":true,"generalLife":8,"itemBuyingPrice":9,"itemSellingPrice":5,"profile":"WeaponLargeSword"},"Weapon_Lsword_005":{"attackPower":18,"attackRange":1.8,"cannotSell":true,"generalLife":12,"itemBuyingPrice":15,"itemSellingPrice":10,"profile":"WeaponLargeSword"},"Weapon_Lsword_006":{"attackPower":36,"attackRange":1.8,"cannotSell":true,"generalLife":16,"itemBuyingPrice":30,"itemSellingPrice":15,"profile":"WeaponLargeSword"},"Weapon_Lsword_010":{"attackPower":9,"attackRange":1.8,"cannotSell":true,"generalLife":12,"itemBuyingPrice":39,"itemSellingPrice":12,"profile":"WeaponLargeSword"},"Weapon_Lsword_011":{"attackPower":27,"attackRange":1.8,"cannotSell":true,"generalLife":18,"itemBuyingPrice":69,"itemSellingPrice":25,"profile":"WeaponLargeSword"},"Weapon_Lsword_012":{"attackPower":45,"attackRange":1.8,"cannotSell":true,"generalLife":24,"itemBuyingPrice":99,"itemSellingPrice":38,"profile":"WeaponLargeSword"},"Weapon_Lsword_013":{"attackPower":30,"attackRange":1.8,"cannotSell":true,"generalLife":15,"itemBuyingPrice":45,"itemSellingPrice":18,"profile":"WeaponLargeSword"},"Weapon_Lsword_014":{"attackPower":45,"attackRange":1.8,"cannotSell":true,"generalLife":20,"itemBuyingPrice":84,"itemSellingPrice":35,"profile":"WeaponLargeSword"},"Weapon_Lsword_015":{"attackPower":60,"attackRange":1.8,"cannotSell":true,"generalLife":25,"itemBuyingPrice":120,"itemSellingPrice":52,"profile":"WeaponLargeSword"},"Weapon_Lsword_016":{"attackPower":36,"attackRange":1.8,"cannotSell":true,"generalLife":20,"itemBuyingPrice":54,"itemSellingPrice":22,"profile":"WeaponLargeSword"},"Weapon_Lsword_017":{"attackPower":54,"attackRange":1.8,"cannotSell":true,"generalLife":25,"itemBuyingPrice":99,"itemSellingPrice":45,"profile":"WeaponLargeSword"},"Weapon_Lsword_018":{"attackPower":78,"attackRange":1.8,"cannotSell":true,"generalLife":35,"itemBuyingPrice":144,"itemSellingPrice":68,"profile":"WeaponLargeSword"},"Weapon_Lsword_019":{"attackPower":15,"attackRange":1.8,"cannotSell":true,"generalLife":5,"profile":"WeaponLargeSword"},"Weapon_Lsword_020":{"attackPower":12,"attackRange":1.8,"cannotSell":true,"generalLife":10,"profile":"WeaponLargeSword"},"Weapon_Lsword_023":{"attackPower":55,"attackRange":1.8,"cannotSell":true,"generalLife":50,"itemBuyingPrice":30,"itemCreatingPrice":1000,"itemSellingPrice":8,"profile":"WeaponLargeSword"},"Weapon_Lsword_024":{"attackPower":52,"attackRange":1.8,"cannotSell":true,"generalLife":40,"itemBuyingPrice":300,"itemSellingPrice":75,"profile":"WeaponLargeSword"},"Weapon_Lsword_027":{"attackPower":22,"attackRange":1.8,"cannotSell":true,"generalLife":30,"itemBuyingPrice":55,"itemSellingPrice":14,"profile":"WeaponLargeSword"},"Weapon_Lsword_029":{"attackPower":28,"attackRange":1.8,"cannotSell":true,"generalLife":30,"itemBuyingPrice":120,"itemSellingPrice":30,"profile":"WeaponLargeSword"},"Weapon_Lsword_030":{"attackPower":18,"attackRange":1.8,"cannotSell":true,"generalLife":52,"itemBuyingPrice":24,"itemSellingPrice":4,"profile":"WeaponLargeSword"},"Weapon_Lsword_031":{"attackPower":12,"attackRange":1.8,"cannotSell":true,"generalLife":40,"itemBuyingPrice":24,"itemSellingPrice":4,"profile":"WeaponLargeSword"},"Weapon_Lsword_032":{"attackPower":3,"attackRange":1.8,"cannotSell":true,"generalLife":47,"itemBuyingPrice":24,"itemSellingPrice":4,"profile":"WeaponLargeSword"},"Weapon_Lsword_033":{"attackPower":34,"attackRange":1.8,"cannotSell":true,"generalLife":50,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponLargeSword"},"Weapon_Lsword_034":{"attackPower":30,"attackRange":1.8,"cannotSell":true,"generalLife":40,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponLargeSword"},"Weapon_Lsword_035":{"attackPower":32,"attackRange":1.8,"cannotSell":true,"generalLife":50,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponLargeSword"},"Weapon_Lsword_036":{"attackPower":15,"attackRange":1.8,"cannotSell":true,"generalLife":30,"itemBuyingPrice":110,"itemSellingPrice":28,"profile":"WeaponLargeSword"},"Weapon_Lsword_037":{"attackPower":42,"attackRange":1.8,"cannotSell":true,"generalLife":40,"itemBuyingPrice":325,"itemSellingPrice":80,"profile":"WeaponLargeSword"},"Weapon_Lsword_038":{"attackPower":14,"attackRange":1.8,"cannotSell":true,"generalLife":8,"itemBuyingPrice":3,"itemSellingPrice":1,"profile":"WeaponLargeSword"},"Weapon_Lsword_041":{"attackPower":32,"attackRange":1.8,"cannotSell":true,"generalLife":25,"itemBuyingPrice":120,"itemSellingPrice":30,"profile":"WeaponLargeSword"},"Weapon_Lsword_045":{"attackPower":16,"attackRange":1.8,"cannotSell":true,"generalLife":6,"itemBuyingPrice":3,"itemSellingPrice":1,"profile":"WeaponLargeSword"},"Weapon_Lsword_047":{"attackPower":72,"attackRange":1.8,"cannotSell":true,"generalLife":15,"itemBuyingPrice":120,"itemSellingPrice":100,"profile":"WeaponLargeSword"},"Weapon_Lsword_051":{"attackPower":25,"attackRange":1.8,"cannotSell":true,"generalLife":40,"itemBuyingPrice":300,"itemSellingPrice":75,"profile":"WeaponLargeSword"},"Weapon_Lsword_054":{"attackPower":60,"attackRange":1.8,"cannotSell":true,"generalLife":60,"itemBuyingPrice":540,"itemSellingPrice":135,"profile":"WeaponLargeSword"},"Weapon_Lsword_055":{"attackPower":50,"attackRange":1.8,"cannotSell":true,"generalLife":35,"itemBuyingPrice":450,"itemSellingPrice":112,"profile":"WeaponLargeSword"},"Weapon_Lsword_056":{"attackPower":1,"attackRange":1.8,"cannotSell":true,"generalLife":25,"itemBuyingPrice":450,"itemSellingPrice":112,"profile":"WeaponLargeSword"},"Weapon_Lsword_057":{"attackPower":48,"attackRange":1.8,"cannotSell":true,"generalLife":50,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponLargeSword"},"Weapon_Lsword_059":{"attackPower":50,"attackRange":1.8,"cannotSell":true,"generalLife":60,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponLargeSword"},"Weapon_Lsword_060":{"attackPower":60,"attackRange":1.8,"cannotSell":true,"generalLife":35,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponLargeSword"},"Weapon_Lsword_074":{"attackPower":40,"attackRange":15.0,"cannotSell":true,"generalLife":25,"profile":"WeaponLargeSword"},"Weapon_Shield_001":{"cannotSell":true,"generalLife":12,"itemBuyingPrice":25,"itemCreatingPrice":10,"itemSellingPrice":6,"profile":"WeaponShield","weaponCommonGuardPower":2},"Weapon_Shield_002":{"cannotSell":true,"generalLife":16,"itemBuyingPrice":70,"itemCreatingPrice":10,"itemSellingPrice":18,"profile":"WeaponShield","weaponCommonGuardPower":16},"Weapon_Shield_003":{"cannotSell":true,"generalLife":23,"itemBuyingPrice":180,"itemCreatingPrice":10,"itemSellingPrice":45,"profile":"WeaponShield","weaponCommonGuardPower":40},"Weapon_Shield_004":{"cannotSell":true,"generalLife":5,"itemBuyingPrice":9,"itemCreatingPrice":10,"itemSellingPrice":5,"profile":"WeaponShield","weaponCommonGuardPower":3},"Weapon_Shield_005":{"cannotSell":true,"generalLife":7,"itemBuyingPrice":15,"itemCreatingPrice":10,"itemSellingPrice":10,"profile":"WeaponShield","weaponCommonGuardPower":10},"Weapon_Shield_006":{"cannotSell":true,"generalLife":8,"itemBuyingPrice":24,"itemCreatingPrice":10,"itemSellingPrice":15,"profile":"WeaponShield","weaponCommonGuardPower":25},"Weapon_Shield_007":{"cannotSell":true,"generalLife":8,"itemBuyingPrice":30,"itemCreatingPrice":10,"itemSellingPrice":10,"profile":"WeaponShield","weaponCommonGuardPower":15},"Weapon_Shield_008":{"cannotSell":true,"generalLife":12,"itemBuyingPrice":60,"itemCreatingPrice":10,"itemSellingPrice":20,"profile":"WeaponShield","weaponCommonGuardPower":22},"Weapon_Shield_009":{"cannotSell":true,"generalLife":15,"itemBuyingPrice":90,"itemCreatingPrice":10,"itemSellingPrice":30,"profile":"WeaponShield","weaponCommonGuardPower":35},"Weapon_Shield_013":{"attackRange":0.5,"cannotSell":true,"generalLife":10,"itemBuyingPrice":45,"itemCreatingPrice":10,"itemSellingPrice":15,"profile":"WeaponShield","weaponCommonGuardPower":18},"Weapon_Shield_014":{"attackRange":0.5,"cannotSell":true,"generalLife":13,"itemBuyingPrice":90,"itemCreatingPrice":10,"itemSellingPrice":30,"profile":"WeaponShield","weaponCommonGuardPower":30},"Weapon_Shield_015":{"attackRange":0.5,"cannotSell":true,"generalLife":20,"itemBuyingPrice":135,"itemCreatingPrice":10,"itemSellingPrice":45,"profile":"WeaponShield","weaponCommonGuardPower":42},"Weapon_Shield_016":{"attackPower":7,"attackRange":0.5,"cannotSell":true,"generalLife":12,"itemBuyingPrice":54,"itemCreatingPrice":10,"itemSellingPrice":18,"profile":"WeaponShield","weaponCommonGuardPower":30},"Weapon_Shield_017":{"attackPower":13,"attackRange":0.5,"cannotSell":true,"generalLife":15,"itemBuyingPrice":105,"itemCreatingPrice":10,"itemSellingPrice":35,"profile":"WeaponShield","weaponCommonGuardPower":44},"Weapon_Shield_018":{"attackPower":21,"attackRange":0.5,"cannotSell":true,"generalLife":20,"itemBuyingPrice":156,"itemCreatingPrice":10,"itemSellingPrice":52,"profile":"WeaponShield","weaponCommonGuardPower":62},"Weapon_Shield_021":{"cannotSell":true,"generalLife":16,"profile":"WeaponShield","weaponCommonGuardPower":3},"Weapon_Shield_022":{"attackRange":0.5,"cannotSell":true,"generalLife":29,"itemBuyingPrice":320,"itemCreatingPrice":10,"itemSellingPrice":80,"profile":"WeaponShield","weaponCommonGuardPower":55},"Weapon_Shield_023":{"attackRange":0.5,"cannotSell":true,"generalLife":18,"itemBuyingPrice":30,"itemCreatingPrice":10,"itemSellingPrice":8,"profile":"WeaponShield","weaponCommonGuardPower":30},"Weapon_Shield_025":{"attackRange":0.5,"cannotSell":true,"generalLife":20,"itemBuyingPrice":220,"itemCreatingPrice":10,"itemSellingPrice":55,"profile":"WeaponShield","weaponCommonGuardPower":18},"Weapon_Shield_026":{"attackRange":0.5,"cannotSell":true,"generalLife":20,"itemBuyingPrice":80,"itemCreatingPrice":10,"itemSellingPrice":20,"profile":"WeaponShield","weaponCommonGuardPower":20},"Weapon_Shield_030":{"cannotSell":true,"generalLife":800,"itemBuyingPrice":3000,"itemCreatingPrice":10,"itemSellingPrice":750,"profile":"WeaponShield","weaponCommonGuardPower":90},"Weapon_Shield_031":{"attackRange":0.5,"cannotSell":true,"generalLife":10,"itemBuyingPrice":15,"itemCreatingPrice":10,"itemSellingPrice":4,"profile":"WeaponShield","weaponCommonGuardPower":3},"Weapon_Shield_032":{"cannotSell":true,"generalLife":10,"itemBuyingPrice":18,"itemCreatingPrice":10,"itemSellingPrice":4,"profile":"WeaponShield","weaponCommonGuardPower":3},"Weapon_Shield_033":{"attackRange":0.5,"cannotSell":true,"generalLife":14,"itemBuyingPrice":300,"itemCreatingPrice":10,"itemSellingPrice":100,"profile":"WeaponShield","weaponCommonGuardPower":70},"Weapon_Shield_034":{"cannotSell":true,"generalLife":12,"itemBuyingPrice":20,"itemCreatingPrice":10,"itemSellingPrice":5,"profile":"WeaponShield","weaponCommonGuardPower":3},"Weapon_Shield_035":{"cannotSell":true,"generalLife":12,"profile":"WeaponShield","weaponCommonGuardPower":4},"Weapon_Shield_036":{"cannotSell":true,"generalLife":26,"itemBuyingPrice":210,"itemCreatingPrice":10,"itemSellingPrice":52,"profile":"WeaponShield","weaponCommonGuardPower":35},"Weapon_Shield_037":{"cannotSell":true,"generalLife":60,"itemBuyingPrice":390,"itemCreatingPrice":10,"itemSellingPrice":98,"profile":"WeaponShield","weaponCommonGuardPower":48},"Weapon_Shield_038":{"cannotSell":true,"generalLife":32,"itemBuyingPrice":375,"itemCreatingPrice":1000,"itemSellingPrice":125,"profile":"WeaponShield","weaponCommonGuardPower":70},"Weapon_Shield_040":{"cannotSell":true,"generalLife":10,"itemBuyingPrice":25,"itemCreatingPrice":10,"itemSellingPrice":6,"profile":"WeaponShield","weaponCommonGuardPower":1},"Weapon_Shield_041":{"cannotSell":true,"generalLife":16,"itemBuyingPrice":25,"itemCreatingPrice":10,"itemSellingPrice":6,"profile":"WeaponShield","weaponCommonGuardPower":16},"Weapon_Shield_042":{"cannotSell":true,"generalLife":16,"itemBuyingPrice":25,"itemCreatingPrice":10,"itemSellingPrice":6,"profile":"WeaponShield","weaponCommonGuardPower":14},"Weapon_Shield_057":{"attackRange":0.5,"cannotSell":true,"generalLife":90,"itemBuyingPrice":320,"itemCreatingPrice":10,"itemSellingPrice":80,"profile":"WeaponShield","weaponCommonGuardPower":65},"Weapon_Spear_001":{"attackPower":3,"attackRange":5.0,"cannotSell":true,"generalLife":30,"itemBuyingPrice":20,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_002":{"attackPower":7,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponSpear"},"Weapon_Spear_003":{"attackPower":13,"attackRange":5.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":180,"itemSellingPrice":45,"profile":"WeaponSpear"},"Weapon_Spear_004":{"attackPower":2,"attackRange":5.0,"cannotSell":true,"generalLife":12,"itemBuyingPrice":9,"itemSellingPrice":5,"profile":"WeaponSpear"},"Weapon_Spear_005":{"attackPower":6,"attackRange":5.0,"cannotSell":true,"generalLife":15,"itemBuyingPrice":15,"itemSellingPrice":10,"profile":"WeaponSpear"},"Weapon_Spear_006":{"attackPower":12,"attackRange":5.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":24,"itemSellingPrice":15,"profile":"WeaponSpear"},"Weapon_Spear_007":{"attackPower":7,"attackRange":5.0,"cannotSell":true,"generalLife":18,"itemBuyingPrice":24,"itemSellingPrice":10,"profile":"WeaponSpear"},"Weapon_Spear_008":{"attackPower":12,"attackRange":5.0,"cannotSell":true,"generalLife":22,"itemBuyingPrice":45,"itemSellingPrice":20,"profile":"WeaponSpear"},"Weapon_Spear_009":{"attackPower":18,"attackRange":5.0,"cannotSell":true,"generalLife":28,"itemBuyingPrice":69,"itemSellingPrice":30,"profile":"WeaponSpear"},"Weapon_Spear_010":{"attackPower":4,"attackRange":5.0,"cannotSell":true,"generalLife":15,"itemBuyingPrice":30,"itemSellingPrice":12,"profile":"WeaponSpear"},"Weapon_Spear_011":{"attackPower":9,"attackRange":5.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":60,"itemSellingPrice":25,"profile":"WeaponSpear"},"Weapon_Spear_012":{"attackPower":15,"attackRange":5.0,"cannotSell":true,"generalLife":25,"itemBuyingPrice":90,"itemSellingPrice":38,"profile":"WeaponSpear"},"Weapon_Spear_013":{"attackPower":10,"attackRange":5.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":39,"itemSellingPrice":18,"profile":"WeaponSpear"},"Weapon_Spear_014":{"attackPower":15,"attackRange":5.0,"cannotSell":true,"generalLife":25,"itemBuyingPrice":75,"itemSellingPrice":35,"profile":"WeaponSpear"},"Weapon_Spear_015":{"attackPower":20,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":114,"itemSellingPrice":52,"profile":"WeaponSpear"},"Weapon_Spear_016":{"attackPower":14,"attackRange":5.0,"cannotSell":true,"generalLife":25,"itemBuyingPrice":45,"itemSellingPrice":22,"profile":"WeaponSpear"},"Weapon_Spear_017":{"attackPower":20,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":90,"itemSellingPrice":45,"profile":"WeaponSpear"},"Weapon_Spear_018":{"attackPower":30,"attackRange":5.0,"cannotSell":true,"generalLife":45,"itemBuyingPrice":135,"itemSellingPrice":68,"profile":"WeaponSpear"},"Weapon_Spear_021":{"attackPower":5,"attackRange":5.0,"cannotSell":true,"generalLife":15,"itemBuyingPrice":20,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_022":{"attackPower":7,"attackRange":5.0,"cannotSell":true,"generalLife":12,"itemBuyingPrice":20,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_023":{"attackPower":30,"attackRange":5.0,"cannotSell":true,"generalLife":50,"itemBuyingPrice":20,"itemCreatingPrice":1000,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_024":{"attackPower":26,"attackRange":5.0,"cannotSell":true,"generalLife":50,"itemBuyingPrice":320,"itemSellingPrice":80,"profile":"WeaponSpear"},"Weapon_Spear_025":{"attackPower":11,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":25,"itemSellingPrice":8,"profile":"WeaponSpear"},"Weapon_Spear_027":{"attackPower":9,"attackRange":5.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponSpear"},"Weapon_Spear_028":{"attackPower":12,"attackRange":5.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":220,"itemSellingPrice":55,"profile":"WeaponSpear"},"Weapon_Spear_029":{"attackPower":16,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":90,"itemSellingPrice":22,"profile":"WeaponSpear"},"Weapon_Spear_030":{"attackPower":6,"attackRange":5.0,"cannotSell":true,"generalLife":20,"itemBuyingPrice":20,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_031":{"attackPower":14,"attackRange":5.0,"cannotSell":true,"generalLife":50,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponSpear"},"Weapon_Spear_032":{"attackPower":10,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":30,"itemSellingPrice":8,"profile":"WeaponSpear"},"Weapon_Spear_033":{"attackPower":24,"attackRange":5.0,"cannotSell":true,"generalLife":50,"itemBuyingPrice":450,"itemSellingPrice":150,"profile":"WeaponSpear"},"Weapon_Spear_034":{"attackPower":20,"attackRange":5.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":450,"itemSellingPrice":150,"profile":"WeaponSpear"},"Weapon_Spear_035":{"attackPower":22,"attackRange":5.0,"cannotSell":true,"generalLife":50,"itemBuyingPrice":450,"itemSellingPrice":150,"profile":"WeaponSpear"},"Weapon_Spear_036":{"attackPower":5,"attackRange":5.0,"cannotSell":true,"generalLife":8,"itemBuyingPrice":3,"itemSellingPrice":1,"profile":"WeaponSpear"},"Weapon_Spear_037":{"attackPower":12,"attackRange":5.0,"cannotSell":true,"generalLife":35,"itemBuyingPrice":130,"itemSellingPrice":32,"profile":"WeaponSpear"},"Weapon_Spear_038":{"attackPower":8,"attackRange":5.0,"cannotSell":true,"generalLife":12,"itemBuyingPrice":20,"itemSellingPrice":7,"profile":"WeaponSpear"},"Weapon_Spear_047":{"attackPower":32,"attackRange":5.0,"cannotSell":true,"generalLife":15,"itemBuyingPrice":120,"itemSellingPrice":100,"profile":"WeaponSpear"},"Weapon_Spear_049":{"attackPower":14,"attackRange":5.0,"cannotSell":true,"generalLife":40,"itemBuyingPrice":400,"itemSellingPrice":100,"profile":"WeaponSpear"},"Weapon_Spear_050":{"attackPower":22,"attackRange":5.0,"cannotSell":true,"generalLife":70,"itemBuyingPrice":400,"itemSellingPrice":100,"profile":"WeaponSpear"},"Weapon_Spear_080":{"attackPower":22,"attackRange":5.0,"generalLife":70,"itemBuyingPrice":400,"itemSellingPrice":100,"profile":"WeaponSpear"},"Weapon_Sword_001":{"attackPower":5,"attackRange":1.6,"cannotSell":true,"generalLife":20,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_002":{"attackPower":14,"attackRange":1.6,"cannotSell":true,"generalLife":23,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_003":{"attackPower":26,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":180,"itemSellingPrice":45,"profile":"WeaponSmallSword"},"Weapon_Sword_004":{"attackPower":4,"attackRange":1.6,"cannotSell":true,"generalLife":12,"itemBuyingPrice":9,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_005":{"attackPower":12,"attackRange":1.6,"cannotSell":true,"generalLife":14,"itemBuyingPrice":15,"itemSellingPrice":10,"profile":"WeaponSmallSword"},"Weapon_Sword_006":{"attackPower":24,"attackRange":1.6,"cannotSell":true,"generalLife":18,"itemBuyingPrice":24,"itemSellingPrice":15,"profile":"WeaponSmallSword"},"Weapon_Sword_007":{"attackPower":14,"attackRange":1.6,"cannotSell":true,"generalLife":17,"itemBuyingPrice":24,"itemSellingPrice":10,"profile":"WeaponSmallSword"},"Weapon_Sword_008":{"attackPower":24,"attackRange":1.6,"cannotSell":true,"generalLife":23,"itemBuyingPrice":45,"itemSellingPrice":20,"profile":"WeaponSmallSword"},"Weapon_Sword_009":{"attackPower":36,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":69,"itemSellingPrice":30,"profile":"WeaponSmallSword"},"Weapon_Sword_013":{"attackPower":20,"attackRange":1.6,"cannotSell":true,"generalLife":17,"itemBuyingPrice":39,"itemSellingPrice":15,"profile":"WeaponSmallSword"},"Weapon_Sword_014":{"attackPower":30,"attackRange":1.6,"cannotSell":true,"generalLife":26,"itemBuyingPrice":75,"itemSellingPrice":30,"profile":"WeaponSmallSword"},"Weapon_Sword_015":{"attackPower":40,"attackRange":1.6,"cannotSell":true,"generalLife":32,"itemBuyingPrice":114,"itemSellingPrice":45,"profile":"WeaponSmallSword"},"Weapon_Sword_016":{"attackPower":24,"attackRange":1.6,"cannotSell":true,"generalLife":26,"itemBuyingPrice":45,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_017":{"attackPower":36,"attackRange":1.6,"cannotSell":true,"generalLife":32,"itemBuyingPrice":90,"itemSellingPrice":35,"profile":"WeaponSmallSword"},"Weapon_Sword_018":{"attackPower":58,"attackRange":1.6,"cannotSell":true,"generalLife":41,"itemBuyingPrice":135,"itemSellingPrice":52,"profile":"WeaponSmallSword"},"Weapon_Sword_019":{"attackPower":5,"attackRange":1.6,"cannotSell":true,"generalLife":5,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Weapon_Sword_020":{"attackPower":12,"attackRange":1.6,"cannotSell":true,"generalLife":8,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Weapon_Sword_021":{"attackPower":6,"attackRange":1.6,"cannotSell":true,"generalLife":8,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_022":{"attackPower":4,"attackRange":1.6,"cannotSell":true,"generalLife":5,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_023":{"attackPower":40,"attackRange":1.6,"cannotSell":true,"generalLife":54,"itemBuyingPrice":20,"itemCreatingPrice":1000,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_024":{"attackPower":36,"attackRange":1.6,"cannotSell":true,"generalLife":36,"itemBuyingPrice":320,"itemSellingPrice":80,"profile":"WeaponSmallSword"},"Weapon_Sword_025":{"attackPower":22,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":25,"itemSellingPrice":6,"profile":"WeaponSmallSword"},"Weapon_Sword_027":{"attackPower":15,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":70,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_029":{"attackPower":16,"attackRange":1.6,"cannotSell":true,"generalLife":23,"itemBuyingPrice":120,"itemSellingPrice":30,"profile":"WeaponSmallSword"},"Weapon_Sword_030":{"attackPower":25,"attackRange":1.6,"cannotSell":true,"generalLife":32,"itemBuyingPrice":220,"itemSellingPrice":55,"profile":"WeaponSmallSword"},"Weapon_Sword_031":{"attackPower":15,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":12,"itemSellingPrice":3,"profile":"WeaponSmallSword"},"Weapon_Sword_033":{"attackPower":24,"attackRange":1.6,"cannotSell":true,"generalLife":36,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponSmallSword"},"Weapon_Sword_034":{"attackPower":20,"attackRange":1.6,"cannotSell":true,"generalLife":30,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponSmallSword"},"Weapon_Sword_035":{"attackPower":22,"attackRange":1.6,"cannotSell":true,"generalLife":36,"itemBuyingPrice":150,"itemSellingPrice":150,"profile":"WeaponSmallSword"},"Weapon_Sword_040":{"attackPower":1,"attackRange":1.6,"cannotSell":true,"generalLife":80,"itemBuyingPrice":15,"itemSellingPrice":2,"profile":"WeaponSmallSword"},"Weapon_Sword_041":{"attackPower":15,"attackRange":1.6,"cannotSell":true,"generalLife":26,"itemBuyingPrice":110,"itemSellingPrice":28,"profile":"WeaponSmallSword"},"Weapon_Sword_043":{"attackPower":2,"attackRange":1.6,"cannotSell":true,"generalLife":8,"itemBuyingPrice":9,"itemSellingPrice":2,"profile":"WeaponSmallSword"},"Weapon_Sword_044":{"attackPower":2,"attackRange":1.6,"cannotSell":true,"generalLife":4,"itemBuyingPrice":3,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Weapon_Sword_047":{"attackPower":48,"attackRange":1.6,"cannotSell":true,"generalLife":14,"itemBuyingPrice":120,"itemSellingPrice":100,"profile":"WeaponSmallSword"},"Weapon_Sword_048":{"attackPower":10,"attackRange":30.0,"cannotSell":true,"generalLife":32,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_049":{"attackPower":10,"attackRange":15.0,"cannotSell":true,"generalLife":32,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_050":{"attackPower":10,"attackRange":30.0,"cannotSell":true,"generalLife":32,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_051":{"attackPower":8,"attackRange":1.6,"cannotSell":true,"generalLife":18,"itemBuyingPrice":100,"itemSellingPrice":25,"profile":"WeaponSmallSword"},"Weapon_Sword_052":{"attackPower":32,"attackRange":1.6,"cannotSell":true,"generalLife":60,"itemBuyingPrice":400,"itemSellingPrice":100,"profile":"WeaponSmallSword"},"Weapon_Sword_053":{"attackPower":16,"attackRange":1.0,"cannotSell":true,"generalLife":14,"itemBuyingPrice":50,"itemSellingPrice":12,"profile":"WeaponSmallSword"},"Weapon_Sword_056":{"attackPower":1,"profile":"WeaponSmallSword"},"Weapon_Sword_057":{"attackPower":28,"attackRange":1.6,"cannotSell":true,"generalLife":45,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_058":{"attackPower":22,"attackRange":1.6,"cannotSell":true,"generalLife":27,"itemBuyingPrice":20,"itemSellingPrice":5,"profile":"WeaponSmallSword"},"Weapon_Sword_059":{"attackPower":20,"attackRange":1.6,"cannotSell":true,"generalLife":20,"itemBuyingPrice":100,"itemSellingPrice":25,"profile":"WeaponSmallSword"},"Weapon_Sword_060":{"attackPower":5,"attackRange":20.0,"cannotSell":true,"generalLife":14,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_061":{"attackPower":5,"attackRange":15.0,"cannotSell":true,"generalLife":14,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_062":{"attackPower":5,"attackRange":20.0,"cannotSell":true,"generalLife":14,"itemBuyingPrice":120,"itemSellingPrice":18,"profile":"WeaponSmallSword"},"Weapon_Sword_070":{"attackPower":30,"attackRange":1.6,"cannotSell":true,"generalLife":40,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Weapon_Sword_073":{"attackPower":40,"attackRange":1.6,"cannotSell":true,"generalLife":25,"profile":"WeaponSmallSword"},"Weapon_Sword_080":{"cannotSell":true,"profile":"WeaponSmallSword"},"Weapon_Sword_081":{"cannotSell":true,"profile":"WeaponSmallSword"},"Weapon_Sword_502":{"attackPower":1,"attackRange":1.6,"cannotSell":true,"generalLife":40,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Weapon_Sword_503":{"attackPower":1,"attackRange":1.6,"generalLife":40,"itemBuyingPrice":1,"itemSellingPrice":1,"profile":"WeaponSmallSword"},"Wizzrobe_WeatherFireBall":{"attackPower":20,"profile":"MapDynamicActive"},"Wizzrobe_WeatherIceBall":{"attackRange":100.0,"profile":"Bullet"},"dyecolor_00":{"itemBuyingPrice":20,"itemStainColor":4,"profile":"Item"},"dyecolor_01":{"itemBuyingPrice":20,"itemStainColor":1,"profile":"Item"},"dyecolor_02":{"itemBuyingPrice":20,"itemStainColor":2,"profile":"Item"},"dyecolor_03":{"itemBuyingPrice":20,"itemStainColor":3,"profile":"Item"},"dyecolor_04":{"itemBuyingPrice":20,"itemStainColor":4,"profile":"Item"},"dyecolor_05":{"itemBuyingPrice":20,"itemStainColor":5,"profile":"Item"},"dyecolor_06":{"itemBuyingPrice":20,"itemStainColor":6,"profile":"Item"},"dyecolor_07":{"itemBuyingPrice":20,"itemStainColor":7,"profile":"Item"},"dyecolor_08":{"itemBuyingPrice":20,"itemStainColor":8,"profile":"Item"},"dyecolor_09":{"itemBuyingPrice":20,"itemStainColor":9,"profile":"Item"},"dyecolor_10":{"itemBuyingPrice":20,"itemStainColor":10,"profile":"Item"},"dyecolor_11":{"itemBuyingPrice":20,"itemStainColor":11,"profile":"Item"},"dyecolor_12":{"itemBuyingPrice":20,"itemStainColor":12,"profile":"Item"},"dyecolor_13":{"itemBuyingPrice":20,"itemStainColor":13,"profile":"Item"},"dyecolor_14":{"itemBuyingPrice":20,"itemStainColor":14,"profile":"Item"},"dyecolor_15":{"itemBuyingPrice":20,"itemStainColor":15,"profile":"Item"}}`); diff --git a/packages/item-system/src/data/ActorData.ts b/packages/item-system/src/data/ActorData.ts new file mode 100644 index 0000000..2839760 --- /dev/null +++ b/packages/item-system/src/data/ActorData.ts @@ -0,0 +1,152 @@ +import { SpecialStatus } from "./enums.ts"; +import { ActorDataMap } from "./ActorData.gen.ts"; + +export const DefaultActorData = { + /** + * The profile user of the actor + * + * Note that if the actor doesn't have any of the other + * data properties, this won't be set + */ + profile: "Unknown" as string, + + /** + * Whether the item is stackable (has CanStack tag) + */ + canStack: false as boolean, + + /** Whether the item not is sellable (has CannotSell tag) */ + cannotSell: false as boolean, + + /** + * The derived special status to display + * + * This could be: + * - SpreadFire for bows, derived from bowIsLeadShot + * - Armor effect, derived from armorEffectEffectType + */ + specialStatus: SpecialStatus.None as SpecialStatus, + + // default gparam comes from Dummy.gparamlist.yaml + + /** + * [GParam] raw string value for armor effects + */ + armorEffectEffectType: "None" as string, + + /** + * Derived from GParam. However, will be 0 unless + * bowIsRapidFire is true + */ + bowRapidFireNum: 0 as number, + + /** + * [GParam] value for multi shot bows + * Some non-multishot bows also have this set to 3, even 5 + */ + bowLeadShotNum: 0 as number, + + /** + * [GParam] Angle for spread fire bows, in degrees. Interestingly, + * this is set to 13 for some non-multishot bows. For multishot + * bows, this is 3 + */ + bowLeadShotAng: 45 as number, + + /** + * [GParam] Number of frames per shot for multishot bows + * This is usually 1 for multishot bows + */ + bowLeadShotInterval: 0 as number, + + /** + * [GParam] (probably) initial speed of the arrow + * This is 8 for RGB + */ + bowArrowFirstSpeed: 4.5 as number, + + /** + * [GParam] (probably) terminal speed of the arrow (4 for ancient) + * bowArrowAcceleration is -0.1 for all bows + */ + bowArrowStabilitySpeed: 3 as number, + + /** + * [GParam] gravity constant experienced by arrows fired by the bow + * + * This is -7 for silver, -2.8 for ancient + */ + bowArrowGravity: -9.8 as number, + + /** [GParam] Misleading name. This is if the bow has default zoom */ + bowIsLongRange: false as boolean, + + /** + * [GParam] How fast the bow charges. Higher means + * bow takes shorter from pressing ZR to ready to fire + * - Higher for falcon, swallow, GEB, RGB + * - Ancient is 0.7 + * + * This also (probably) determines how many arrows + * can come out of multishot. Probably min(ceil(1 / bowArrowChargeRate), 10) + */ + bowArrowChargeRate: 1 as number, + + /** + * [GParam] How fast the bow reloads. Lower means + * bow takes shorter to be able to fire again after firing + * + * This is 0.8 for RGB + */ + bowArrowReloadRate: 1 as number, + + /** [GParam] If the bow is ancient bow */ + bowIsGuardPierce: false as boolean, + + /** [GParam] Power for weapon/bow/shield(bashing) */ + attackPower: 0 as number, + + /** [GParam] Range for weapon/bow/shield */ + attackRange: 0 as number, + + /** [GParam] Durability */ + generalLife: 100 as number, + + /** [GParam] If durability decreases with use */ + generalIsLifeInfinite: false as boolean, + + /** [GParam] selling price */ + itemSellingPrice: -1 as number, + /** [GParam] buying price */ + itemBuyingPrice: -1 as number, + /** [GParam] creating price */ + itemCreatingPrice: -1 as number, + + /** [GParam] If the item is a dye, the color of it */ + itemStainColor: -1 as number, + + /** [GParam] Guard power for shields */ + weaponCommonGuardPower: 0 as number, + + /** [GParam] 0 for not armor, 1-5 for no star to 4 star */ + armorStarNum: 0 as number, + + /** [GParam] Defense for armor */ + armorDefenceAddLevel: 0 as number, +} as const; + +export type ActorData = typeof DefaultActorData; + +/** Get the data property of the actor, or default if the actor doesn't have the property */ +export const getActorParam = (actor: string, key: K): ActorData[K] => { + const data = ActorDataMap[actor]; + if (!data || !(key in data)) { + return DefaultActorData[key]; + } + return data[key]; +} + +/** Check if the actor has the property */ +export const hasActorParam = (actor: string, key: K): boolean => { + return key in ActorDataMap[actor]; +} diff --git a/packages/item-system/src/data/ItemSlotInfo.ts b/packages/item-system/src/data/ItemSlotInfo.ts new file mode 100644 index 0000000..4b3e41d --- /dev/null +++ b/packages/item-system/src/data/ItemSlotInfo.ts @@ -0,0 +1,112 @@ +import type { CookEffect, ItemUse, PouchItemType } from "./enums.ts"; + +/** + * Information to display an item slot + * + * These are data derived from the native PouchItem class + * and simulator runtime info. Data that can be looked up + * from the item's parameters should not be included here. + */ +export type ItemSlotInfo = { + /** + * Name of the actor, from PouchItem::mName + * + * This is what will be used to look up extra data for the item + */ + actorName: string, + + /** + * PouchItem::mType + * + * Note this is raw memory value and may not be a valid enum value + */ + itemType: PouchItemType | number, + + /** + * PouchItem::mItemUse + * + * Note this is raw memory value and may not be a valid enum value + */ + itemUse: ItemUse | number, + + /** + * PouchItem::mValue + * + * This is stack size or durability * 100 + */ + value: number, + + /** PouchItem::mEquipped */ + isEquipped: boolean, + + /** PouchItem::mInInventory */ + isInInventory: boolean, + + /** + * This is either the weapon modifier value, + * or the HP recovery value for food (in quarter-hearts) + */ + modEffectValue: number, + + /** + * For food with a timed effect, this is the duration in seconds. + * For stamina, this is the raw value + */ + modEffectDuration: number, + + /** + * For weapon modifier, this is the flag bitset. For food, + * this is the sell price + */ + modSellPrice: number, + + /** + * Effect ID for the food + * + * Note this is raw memory value and may not be a valid enum value + */ + modEffectId: CookEffect | number, + + /** + * The level of the effect, *usually* 1-3. However this + * is the raw memory value and may not be valid + */ + modEffectLevel: number, + + /** + * PouchItem::mIngredients. Length should always be 5 + */ + ingredientActorNames: string[], + + /** + * The item's position in the item list. + * + * If the item is in the unallocated pool, this is its position + * in the unallocated pool (stack). 0 is the top of the stack/beginning + * of the list + */ + listPosition: number, + + /** If the item is currently in the unallocated pool */ + unallocated: boolean, + + /** + * The item's position in the pool + * + * This basically serves as a unique pointer to the item + */ + poolPosition: number, + + /** If the item is in "broken" slot, i.e. will be transferred on reload */ + isInBrokenSlot: boolean, + + /** + * Number of items held if the item is being held by the player + */ + holdingCount: number, + + /** + * Enable the prompt entangled state for this slot + */ + promptEntangled: boolean, +} diff --git a/packages/item-system/src/data/ModifierInfo.ts b/packages/item-system/src/data/ModifierInfo.ts new file mode 100644 index 0000000..2ca7086 --- /dev/null +++ b/packages/item-system/src/data/ModifierInfo.ts @@ -0,0 +1,256 @@ +import { getActorParam } from "./ActorData.ts"; +import { CookEffect, effectToStatus, modifierToStatus, PouchItemType, SpecialStatus, WeaponModifier } from "./enums.ts"; +import type { ItemSlotInfo } from "./ItemSlotInfo.ts"; + +/** Modifier display info derived from ItemSlotInfo and ActorData */ +export type ModifierInfo = { + /** The special status to display on the item slot */ + status: SpecialStatus + /** + * The icon to display for the special status + * + * Some status corresponds to multiple icons, like AddPower + * for weapon and bow + */ + statusIcon: string, + + /** Value to display next to the modifier icon in the item slot */ + iconValue: string, + + /** Extra details for each of the weapon modifiers */ + details: ModifierDetail[], + +}; + +/** Extra detail for each of the weapon modifiers */ +export type ModifierDetail = { + /** The special status corresponding to the modifier */ + status: SpecialStatus, + /** The special status icon corresponding to the modifier */ + statusIcon: string, + /** If the modifier is active on the item type */ + active: boolean, + /** + * The display value of the modifier + * + * Number for AddPower, AddGuard, SpreadFire, percentage + * for LongThrow, RapidFire, SurfMaster + */ + modifierValue: string, +} + + + +/** Get the modifier info for an item slot */ +export const getModifierInfo = (info: ItemSlotInfo): ModifierInfo => { + const { actorName, itemType, modEffectId, modSellPrice } = info; + // only display WeaponModifier for equipments + if (itemType === PouchItemType.Sword || itemType === PouchItemType.Bow || itemType === PouchItemType.Shield) { + return getModifierInfoForEquipments(info); + } + // get from cook data + let status = SpecialStatus.None; + if (modEffectId !== CookEffect.None) { + status = effectToStatus(modEffectId); + } + const defaultData = getDefaultModifierInfoForActor(actorName); + // override status if any + if (status !== SpecialStatus.None) { + defaultData.status = status; + defaultData.statusIcon = SpecialStatus[status]; + } + // display price if it's odd, because it's probably used for WMC + const iconValue = (modSellPrice > 1 && modSellPrice % 2 === 1) ? `$${modSellPrice}` : ""; + defaultData.iconValue = iconValue; + + return defaultData; +} + +export const getModifierInfoForEquipments = (info: ItemSlotInfo): ModifierInfo => { + const { actorName, itemType, modEffectValue, modSellPrice } = info; + const specialStatus = getWeaponSpecialStatusToDisplay(modSellPrice); + let iconValue = 0; + + if (specialStatus === SpecialStatus.None) { + return getDefaultModifierInfoForActor(actorName); + } + + // only display value for AddPower and AddGuard + if (specialStatus === SpecialStatus.AddPower) { + iconValue += modEffectValue; + } + // value is doubled if both AddPower and AddGuard are present for shields + if (itemType === PouchItemType.Shield && (modSellPrice & WeaponModifier.AddGuard) !== 0) { + iconValue += modEffectValue; + } + + // Fix multishot icon + let statusIcon = SpecialStatus[specialStatus]; + if (specialStatus === SpecialStatus.SpreadFire) { + statusIcon = getMultishotIcon(modEffectValue); + } + + // Fix bow attack up + if (itemType === PouchItemType.Bow) { + if (specialStatus === SpecialStatus.AddPower) { + statusIcon = "AddPower_Bow"; + } else if (specialStatus === SpecialStatus.AddPowerPlus) { + statusIcon = "AddPowerPlus_Bow"; + } + } + + // get effect details + const details: ModifierDetail[] = []; + const yellow = (modSellPrice & WeaponModifier.Yellow) !== 0; + if (modSellPrice & WeaponModifier.AddPower) { + details.push({ + status: SpecialStatus.AddPower, + statusIcon: itemType === PouchItemType.Bow ? (yellow ? "AddPowerPlus_Bow" : "AddPower_Bow") : (yellow?"AddPowerPlus":"AddPower"), + active: true, // attack up is always active + modifierValue: `${modEffectValue}`, + }); + } + if (modSellPrice & WeaponModifier.AddLife) { + details.push({ + status: SpecialStatus.AddLife, + statusIcon: yellow ? "AddLifePlus" : "AddLife", + active: true, // durability up, always active, although it doesn't do anything + modifierValue: "" + }); + } + if (modSellPrice & WeaponModifier.AddGuard) { + details.push({ + status: SpecialStatus.AddGuard, + statusIcon: yellow ? "AddGuardPlus" : "AddGuard", + active: itemType === PouchItemType.Shield, + modifierValue: `${modEffectValue}` + }); + } + if (modSellPrice & WeaponModifier.Critical) { + details.push({ + status: SpecialStatus.Critical, + statusIcon: "Critical", + active: itemType === PouchItemType.Sword, + modifierValue: "" + }); + } + if (modSellPrice & WeaponModifier.LongThrow) { + details.push({ + status: SpecialStatus.LongThrow, + statusIcon: "LongThrow", + active: itemType === PouchItemType.Sword, + modifierValue: getModifierPercentDifference(modEffectValue) + }); + } + if (modSellPrice & WeaponModifier.SpreadFire) { + // This is guess on how it works based on experience + // multishot is capped at 10. The faster the bow shoots, fewer arrows come out + const bowChargeRate = getActorParam(actorName, "bowArrowChargeRate"); + const quickShotMultiplier = (modSellPrice & WeaponModifier.RapidFire) !== 0 ? (modEffectValue / 1000) : 1; + const multishot = 10 / (bowChargeRate * quickShotMultiplier); + const modifierValue = multishot >= 10 ? "10" : `~${multishot.toFixed(2)}`; + details.push({ + status: SpecialStatus.SpreadFire, + statusIcon: getMultishotIcon(modEffectValue), + active: itemType === PouchItemType.Bow, + modifierValue + }); + } + if (modSellPrice & WeaponModifier.Zoom) { + details.push({ + status: SpecialStatus.Zoom, + statusIcon: "Zoom", + active: itemType === PouchItemType.Bow, + modifierValue: "" + }); + } + if (modSellPrice & WeaponModifier.RapidFire) { + details.push({ + status: SpecialStatus.RapidFire, + statusIcon: "RapidFire", + active: itemType === PouchItemType.Bow, + modifierValue: getModifierPercentDifference(modEffectValue) + }); + } + if (modSellPrice & WeaponModifier.SurfMaster) { + details.push({ + status: SpecialStatus.SurfMaster, + statusIcon: "SurfMaster", + active: itemType === PouchItemType.Shield, + modifierValue: getModifierPercentDifference(modEffectValue) + }); + } + + return { + status: specialStatus, + statusIcon, + iconValue: iconValue ? `+${iconValue}` : "", + details, + } +} + +const getWeaponSpecialStatusToDisplay = (modifierSet: number): SpecialStatus => { + // 0x7100aa7290 in 1.5.0 + // https://discord.com/channels/269611402854006785/269616041435332608/1041497732474482698 + // select the modifier to display from the bitset + const applicableModifiers = [ + WeaponModifier.AddPower, + WeaponModifier.AddLife, + WeaponModifier.AddGuard, + WeaponModifier.Critical, + WeaponModifier.LongThrow, + WeaponModifier.SpreadFire, + WeaponModifier.Zoom, + WeaponModifier.RapidFire, + WeaponModifier.SurfMaster, + ]; + + let selectedModifier: WeaponModifier = WeaponModifier.None; + for (let i = 0; i < applicableModifiers.length; i++) { + if ( + (applicableModifiers[i] & modifierSet) !== + WeaponModifier.None + ) { + selectedModifier = applicableModifiers[i]; + break; + } + } + + return modifierToStatus(selectedModifier, (modifierSet & WeaponModifier.Yellow) !== 0); +} + +export const getDefaultModifierInfoForActor = (actorName: string): ModifierInfo => { + const status = getActorParam(actorName, "specialStatus"); + + let statusIcon = SpecialStatus[status]; + // convert to the correct multishot icon + if (status === SpecialStatus.SpreadFire) { + const num = getActorParam(actorName, "bowLeadShotNum"); + statusIcon = getMultishotIcon(num); + } + return { + status, + statusIcon, + iconValue: "", + details: [], + } +} + +export const getMultishotIcon = (num: number): string => { + if (num <= 3) { + return "SpreadFire_3"; + } + if (num <= 5) { + return "SpreadFire_5"; + } + return "SpreadFire_X"; +} + +const getModifierPercentDifference = (value: number): string => { + if (value === 1000) { + return "0%"; + } + const percentage = (value - 1000) / 10; + + return `${percentage > 0 ? "+" : ""}${percentage.toFixed(1)}%`; +}; diff --git a/packages/item-system/src/data/enums.ts b/packages/item-system/src/data/enums.ts new file mode 100644 index 0000000..fa60fcc --- /dev/null +++ b/packages/item-system/src/data/enums.ts @@ -0,0 +1,165 @@ + +/** + * uking::ui::PouchItemType + */ +export enum PouchItemType { + Sword = 0, + Bow = 1, + Arrow = 2, + Shield = 3, + ArmorHead = 4, + ArmorUpper = 5, + ArmorLower = 6, + Material = 7, + Food = 8, + KeyItem = 9, + Invalid = -1, +} + +/** + * uking::ui::ItemUse + */ +export enum ItemUse { + WeaponSmallSword = 0, + WeaponLargeSword = 1, + WeaponSpear = 2, + WeaponBow = 3, + WeaponShield = 4, + ArmorHead = 5, + ArmorUpper = 6, + ArmorLower = 7, + Item = 8, + ImportantItem = 9, + CureItem = 10, + Invalid = -1, +} + +/** uking::CookEffectId */ +export enum CookEffect { + None = -1, + LifeRecover = 1, + LifeMaxUp = 2, + ResistHot = 4, + ResistCold = 5, + ResistElectric = 6, + AttackUp = 10, + DefenseUp = 11, + Quietness = 12, + // note the name we use internally for skybook is different + // for decomp, it's MovingSpeed + AllSpeed = 13, + GutsRecover = 14, + ExGutsMaxUp = 15, + Fireproof = 16, +} + +/** + * Internal used special status enum + * + * These correspond to modifier icons + * These are used in generated data - DO NOT CHANGE + */ +export enum SpecialStatus { + None = 0, + AddGuard = 1, + AddGuardPlus, + AddLife, + AddLifePlus, + AddPower, + AddPowerPlus, + AllSpeed, + AttackUp, + ClimbSpeedUp, + Critical, + DefenseUp, + ExGutsMaxUp, + Fireproof, // "ResistBurn", not the fire-immunity effect + GutsRecover, + LifeMaxUp, + LongThrow, + Quietness, + RapidFire, + ReduceAncientEnemyDamge, // not a typo + ResistCold, + ResistElectric, + ResistFreeze, + ResistHot, + ResistLightning, + SandMoveSpeedUp, + SnowMovingSpeed, + SpreadFire, + SurfMaster, + SwimSpeedUp, + Zoom, +} + +/** uking::act::WeaponModifier */ +export const WeaponModifier = { + None: 0x0, + AddPower: 0x1, + AddLife: 0x2, + Critical: 0x4, + LongThrow: 0x8, + SpreadFire: 0x10, + Zoom: 0x20, + RapidFire: 0x40, + SurfMaster: 0x80, + AddGuard: 0x100, + Yellow: 0x80000000 +} as const; + +export type WeaponModifier = typeof WeaponModifier[keyof typeof WeaponModifier]; + +/** Convert a WeaponModifier to a SpecialStatus */ +export const modifierToStatus = (modifier: WeaponModifier, yellow: boolean): SpecialStatus => { + switch(modifier) { + case WeaponModifier.AddPower: + return yellow ? SpecialStatus.AddPowerPlus : SpecialStatus.AddPower; + case WeaponModifier.AddLife: + return yellow ? SpecialStatus.AddLifePlus : SpecialStatus.AddLife; + case WeaponModifier.AddGuard: + return yellow ? SpecialStatus.AddGuardPlus : SpecialStatus.AddGuard; + case WeaponModifier.Critical: + return SpecialStatus.Critical; + case WeaponModifier.LongThrow: + return SpecialStatus.LongThrow; + case WeaponModifier.SpreadFire: + return SpecialStatus.SpreadFire; + case WeaponModifier.Zoom: + return SpecialStatus.Zoom; + case WeaponModifier.RapidFire: + return SpecialStatus.RapidFire; + case WeaponModifier.SurfMaster: + return SpecialStatus.SurfMaster; + } + return SpecialStatus.None; +} + +/** Convert a CookEffect to a SpecialStatus */ +export const effectToStatus = (effect: CookEffect): SpecialStatus => { + switch(effect) { + case CookEffect.LifeMaxUp: + return SpecialStatus.LifeMaxUp; + case CookEffect.ResistHot: + return SpecialStatus.ResistHot; + case CookEffect.ResistCold: + return SpecialStatus.ResistCold; + case CookEffect.ResistElectric: + return SpecialStatus.ResistElectric; + case CookEffect.AttackUp: + return SpecialStatus.AttackUp; + case CookEffect.DefenseUp: + return SpecialStatus.DefenseUp; + case CookEffect.Quietness: + return SpecialStatus.Quietness; + case CookEffect.AllSpeed: + return SpecialStatus.AllSpeed; + case CookEffect.GutsRecover: + return SpecialStatus.GutsRecover; + case CookEffect.ExGutsMaxUp: + return SpecialStatus.ExGutsMaxUp; + case CookEffect.Fireproof: + return SpecialStatus.Fireproof; + } + return SpecialStatus.None; +} diff --git a/packages/item-system/src/index.ts b/packages/item-system/src/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/item-system/testpage/main.tsx b/packages/item-system/testpage/main.tsx new file mode 100644 index 0000000..0e21b35 --- /dev/null +++ b/packages/item-system/testpage/main.tsx @@ -0,0 +1,248 @@ +import React, { useState } from "react"; +import { createRoot } from "react-dom/client"; +import { FluentProvider, Switch, webDarkTheme, webLightTheme } from "@fluentui/react-components"; + +import { ItemTooltipProvider } from "../src/ItemTooltipProvider"; +import { ItemSlotInfo } from "../src/data/ItemSlotInfo.ts"; +import { CookEffect, ItemUse, PouchItemType } from "../src/data/enums.ts"; + +import { ItemSlot } from "../src/ItemSlot"; +import { ItemTooltip } from "../src/ItemTooltip.tsx"; +import { initI18n } from "skybook-localization"; + +const DUMMY: ItemSlotInfo = { + actorName: "Dummy", + itemType: PouchItemType.Sword, + itemUse: ItemUse.WeaponSmallSword, + value: 0, + isEquipped: false, + isInInventory: true, + modEffectValue: 0, + modEffectDuration: 0, + modSellPrice: 0, + modEffectId: CookEffect.None, + modEffectLevel: 0, + ingredientActorNames: [], + listPosition: 0, + unallocated: false, + poolPosition: 0, + isInBrokenSlot: false, + holdingCount: 0, + promptEntangled: false, +} + +const TEST_ITEMS: ItemSlotInfo[] = [ + { + ...DUMMY, + actorName: "Weapon_Sword_070", + itemType: PouchItemType.Sword, + itemUse: ItemUse.WeaponSmallSword, + value: 4000, + }, + { + ...DUMMY, + actorName: "Obj_HeroSoul_Zora", + itemType: PouchItemType.KeyItem, + }, + { + ...DUMMY, + actorName: "Item_Ore_A", + itemType: PouchItemType.Material, + value: 99999, + }, + { + ...DUMMY, + actorName: "Weapon_Lsword_010", + itemType: PouchItemType.Sword, + itemUse: ItemUse.WeaponLargeSword, + value: 3850, + }, + { + ...DUMMY, + actorName: "Item_PlantGet_Q", + itemType: PouchItemType.Material, + value: 5, + holdingCount: 4, + }, + { + ...DUMMY, + actorName: "Obj_DLC_HeroSoul_Goron", + itemType: PouchItemType.KeyItem, + }, + { + ...DUMMY, + actorName: "Weapon_Sword_502", + itemType: PouchItemType.Sword, + itemUse: ItemUse.WeaponSmallSword, + value: 100, + }, + { + ...DUMMY, + actorName: "Armor_011_Lower", + itemType: PouchItemType.ArmorLower, + itemUse: ItemUse.ArmorLower, + value: 1, + }, + { + ...DUMMY, + actorName: "Weapon_Bow_028", + itemType: PouchItemType.Bow, + itemUse: ItemUse.WeaponBow, + value: 6000, + }, + { + ...DUMMY, + actorName: "Weapon_Bow_028", + itemType: PouchItemType.Bow, + itemUse: ItemUse.WeaponBow, + value: 6000, + modEffectValue: 120, + modSellPrice: 147, + }, + { + ...DUMMY, + actorName: "Weapon_Shield_001", + itemType: PouchItemType.Shield, + itemUse: ItemUse.WeaponShield, + value: 1000, + modEffectValue: 120, + modSellPrice: 0xffffffff, + }, + { + ...DUMMY, + actorName: "Item_Cook_A_01", + itemType: PouchItemType.Food, + itemUse: ItemUse.CureItem, + value: 1, + modEffectValue: 120, + isInInventory: false, + modSellPrice: 115, + }, + { + ...DUMMY, + actorName: "Item_Cook_C_17", + itemType: PouchItemType.Food, + itemUse: ItemUse.CureItem, + value: 1, + modEffectValue: 120, + modEffectId: CookEffect.ExGutsMaxUp, + modSellPrice: 115, + }, + { + ...DUMMY, + actorName: "Armor_075_Head", + itemType: PouchItemType.ArmorUpper, + itemUse: ItemUse.ArmorUpper, + value: 1, + }, + { + ...DUMMY, + actorName: "Item_Cook_C_17", + itemType: PouchItemType.Food, + itemUse: ItemUse.CureItem, + value: 1, + modEffectValue: 25, + modEffectId: CookEffect.LifeMaxUp, + }, + { + ...DUMMY, + actorName: "Item_Cook_C_17", + itemType: PouchItemType.Food, + itemUse: ItemUse.CureItem, + value: 1, + modEffectValue: 25, + modEffectId: CookEffect.GutsRecover, + modEffectLevel: 1000, + }, + { + ...DUMMY, + actorName: "Item_Cook_C_17", + itemType: 78, + itemUse: 87, + value: 1, + modEffectValue: 40, + modEffectId: CookEffect.AllSpeed, + modEffectLevel: 3, + modEffectDuration: 3600, + }, +]; + +const App: React.FC = () => { + const [cheap, setCheap] = useState(false); + const [isEquipped, setIsEquipped] = useState(false); + const [isInBrokenSlot, setIsInBrokenSlot] = useState(false); + const [deactive, setDeactive] = useState(false); + const [badlyDamaged, setBadlyDamaged] = useState(false); + const [animation, setAnimation] = useState(true); + const [entangled, setEntangled] = useState(false); + + const items = TEST_ITEMS.map((item, i) => { + return { + ...item, isEquipped, isInBrokenSlot, listPosition: i, + promptEntangled: entangled, + ...(badlyDamaged ? { value: 200 } : {}) + } + }); + + return <> +
+ { + setCheap(!!checked); + }} /> + { + setIsEquipped(!!checked); + }} /> + { + setIsInBrokenSlot(!!checked); + }} /> + { + setDeactive(!!checked); + }} /> + { + setBadlyDamaged(!!checked); + }} /> + { + setAnimation(!!checked); + }} /> + { + setEntangled(!!checked); + }} /> +
+
+ { + items.map((item, index) => { + return ( + + + + ); + }) + } +
+ ; +}; + +void (async function main(){ + await initI18n(); + + + const root = document.getElementById('root'); + if (root) { + createRoot(root).render( + + + + + + + + ); + } + +})() + diff --git a/packages/item-system/tsconfig.app.json b/packages/item-system/tsconfig.app.json new file mode 100644 index 0000000..6461f97 --- /dev/null +++ b/packages/item-system/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../config/tsconfig-vite-app.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + }, + "include": ["src", "testpage"] +} diff --git a/packages/item-system/tsconfig.json b/packages/item-system/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/packages/item-system/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/packages/item-system/tsconfig.node.json b/packages/item-system/tsconfig.node.json new file mode 100644 index 0000000..c890797 --- /dev/null +++ b/packages/item-system/tsconfig.node.json @@ -0,0 +1,7 @@ +{ + "extends": "../../config/tsconfig-tool.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + }, + "include": ["vite.config.ts"] +} diff --git a/packages/item-system/vite.config.ts b/packages/item-system/vite.config.ts new file mode 100644 index 0000000..9013ec4 --- /dev/null +++ b/packages/item-system/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import yaml from "@modyfi/vite-plugin-yaml"; + +// import esbuildImportMetaUrlPlugin from "@codingame/esbuild-import-meta-url-plugin"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), yaml()], + + // optimizeDeps: { + // esbuildOptions: { + // plugins: [esbuildImportMetaUrlPlugin] + // } + // } +}) + diff --git a/packages/localization/.gitignore b/packages/localization/.gitignore new file mode 100644 index 0000000..d1d744a --- /dev/null +++ b/packages/localization/.gitignore @@ -0,0 +1,2 @@ +src/generated/*.yaml +/node_modules/ diff --git a/packages/localization/Taskfile.yml b/packages/localization/Taskfile.yml new file mode 100644 index 0000000..14d1157 --- /dev/null +++ b/packages/localization/Taskfile.yml @@ -0,0 +1,7 @@ +version: '3' + +tasks: + push: + desc: Push generated files. Requires gcloud access + cmds: + - gcloud storage cp src/generated/*.yaml gs://ist-private/i18n/generated diff --git a/packages/localization/package.json b/packages/localization/package.json new file mode 100644 index 0000000..7cf2011 --- /dev/null +++ b/packages/localization/package.json @@ -0,0 +1,14 @@ +{ + "name": "skybook-localization", + "private": true, + "version": "0.0.0", + "type": "module", + "dependencies": { + "@pistonite/pure": "*", + "i18next": "^24.2.0", + "react-i18next": "^15.2.0" + }, + "exports": { + ".": "./src/index.ts" + } +} diff --git a/packages/localization/src/index.ts b/packages/localization/src/index.ts new file mode 100644 index 0000000..ce5d8fc --- /dev/null +++ b/packages/localization/src/index.ts @@ -0,0 +1,85 @@ +import type { BackendModule } from "i18next"; +import i18next from "i18next"; +import { initReactI18next, useTranslation } from "react-i18next"; +import { convertToSupportedLocale, detectLocale, initLocale } from "@pistonite/pure/pref"; +import { useCallback } from "react"; + +export const backend: BackendModule = { + type: "backend", + init: () => { + // no init needed + }, + read: async (language: string, namespace: string) => { + if (namespace === "translation" || language === "dev") { + // don't load the default translation namespace + return undefined; + } + const locale = convertToSupportedLocale(language); + console.log(locale, namespace); + let strings; + try { + strings = await import(`./${namespace}/${locale}.yaml`); + console.log(strings); + } catch(e) { + console.error(e); + try { + strings = await import(`./${namespace}/en-US.yaml`); + } catch(e) { + console.error(e); + return undefined; + } + console.warn(`${language} is not supported for ${namespace} namespace. Falling back to en-US.`); + } + return strings.default; + } +} + +export const SupportedLocales = + [ + "de-DE", + "en-US", + "es-ES", + "fr-FR", + "it-IT", + "ja-JP", "ko-KR", + "nl-NL", + "ru-RU", "zh-CN", "zh-TW" + ] as const; + +export const initI18n = async () => { + initLocale({ + supported: SupportedLocales, + default: "en-US", + persist: true, + }); + + await i18next.use(detectLocale).use(backend).use(initReactI18next).init(); +} + +export const translateUI = (key: string, options?: Record) => { + return i18next.t(`ui:${key}`, options); +} +export const translateGenerated = (key: string, options?: Record) => { + const value = i18next.t(`generated:${key}`, options); + if (value === key) { + return ""; + } + return value; +} + +export const useUITranslation = () => { + const {t} = useTranslation("ui"); + return t; +} + +export const useGeneratedTranslation = () => { + const {t} = useTranslation("generated", {nsMode: "default"}); + // return empty string if the key is not found, similar to the game + return useCallback((key: string, options?: Record) => { + const value = t(key, options); + if (value === key) { + return ""; + } + return value; + }, [t]); +} diff --git a/packages/localization/src/ui/en-US.yaml b/packages/localization/src/ui/en-US.yaml new file mode 100644 index 0000000..abab6ef --- /dev/null +++ b/packages/localization/src/ui/en-US.yaml @@ -0,0 +1,43 @@ + +button.close: Close +button.popout: Pop-out to a new window + +button.open_extension: Extensions +button.launch: Launch +button.cancel: Cancel + +status.not_available_platform: Not available for current platform +status.not_available_window_size: Not available because the window is too small + +dialog.extensions.title: Extensions +dialog.extensions.desc: Launch an extension tool or change its configuration +field.select_extension: Select an extension +radio.extension_open_mode.primary: Open in primary view +radio.extension_open_mode.secondary: Open in secondary view +radio.extension_open_mode.popout: Pop-out to a new window +field.extension.remember: Remember my choice +field.extension.remember.desc: Only effective after clicking "Launch". You can always come back here and change your preference + +extension.editor.name: Script Editor +extension.editor.desc: Edit the script to modify the steps in the simulation +extension.stub1.name: blaasldkfjasd asdgak sdgfa lskdhgal + + +# Item Slot Tooltip +tooltip.value: "Value: {{value}}" +tooltip.equipped: "Equipped" +tooltip.translucent: "Translucent" +tooltip.holding: "Holding {{holding}}" + +tooltip.cook.price: "Sells for ${{price}}" + +tooltip.category: "Category: {pouch_category}" +tooltip.slot: "Slot #{slot_number}, Pos #{position}" +tooltip.transfer_slot: "Will be transferred" + +tooltip.profile: "Profile: {profile}" +tooltip.power: "Power: {gparam_attack_power}" +tooltip.life: "Life: {gparam_general_life}" +tooltip.life_infinite: "Life: Infinite [{gparam_general_life}]" # generalIsLifeInfinite +tooltip.buy_price: "Buying Price: {gparam_item_buying_price}" +tooltip.sell_price: "Selling Price: {gparam_item_selling_price}" diff --git a/packages/localization/tsconfig.json b/packages/localization/tsconfig.json new file mode 100644 index 0000000..1f7887e --- /dev/null +++ b/packages/localization/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../config/tsconfig-vite-app.json", + "include": ["src"], +} diff --git a/packages/monaco-editor-contrib/.gitignore b/packages/monaco-editor-contrib/.gitignore new file mode 100644 index 0000000..a55429a --- /dev/null +++ b/packages/monaco-editor-contrib/.gitignore @@ -0,0 +1,5 @@ +/lib +/esm +/monaco.d.ts +/package.original.json + diff --git a/packages/monaco-editor-contrib/LICENSE b/packages/monaco-editor-contrib/LICENSE new file mode 100644 index 0000000..76fdc58 --- /dev/null +++ b/packages/monaco-editor-contrib/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 - present Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/monaco-editor-contrib/Taskfile.yml b/packages/monaco-editor-contrib/Taskfile.yml new file mode 100644 index 0000000..34a1ca2 --- /dev/null +++ b/packages/monaco-editor-contrib/Taskfile.yml @@ -0,0 +1,17 @@ +version: '3' + +tasks: + clean: + cmds: + - rm -f monaco.d.ts + - rm -f package.original.json + - rm -rf lib + - rm -rf esm + - mkdir lib + patch: + cmds: + - deno --allow-read --allow-write patch.ts + - mv lib/monaco-editor/monaco.d.ts . + - mv lib/monaco-editor/esm . + - mv lib/monaco-editor/package.json package.original.json + - rm -rf lib diff --git a/packages/monaco-editor-contrib/package.json b/packages/monaco-editor-contrib/package.json new file mode 100644 index 0000000..11e6f64 --- /dev/null +++ b/packages/monaco-editor-contrib/package.json @@ -0,0 +1,21 @@ +{ + "name": "monaco-editor-contrib", + "version": "0.52.2", + "license": "MIT", + "typings": "./esm/vs/editor/editor.api.d.ts", + "module": "./esm/vs/editor/editor.main.js", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/monaco-editor" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "monaco-editor": "0.52.2" + }, + "alias": { + "process": false, + "buffer": false + }, + "vscodeCommitId": "a7d9e2c32d573e29e68975838196722ae9bb0f15", + "monacoCommitId": "404545bded1df6ffa41ea0af4e8ddb219018c6c1" +} diff --git a/packages/monaco-editor-contrib/patch.ts b/packages/monaco-editor-contrib/patch.ts new file mode 100644 index 0000000..1bb9a82 --- /dev/null +++ b/packages/monaco-editor-contrib/patch.ts @@ -0,0 +1,76 @@ +/** + * Patches TS Worker to expose getEncodedSemanticClassifcations + * according to the POC here: + * https://github.com/Pistonight/monaco-editor/commit/ac884678bc17c0eafe174a9cab84510f3b68b4ed + */ + +import fs from "node:fs"; + +let lines: string[] = []; +let currentLine = 0; +let outLines: string[] = []; + +const patchFile = (file: string, fn: () => void) => { + const oldFile = file + ".old"; + if (fs.existsSync(oldFile)) { + if (fs.existsSync(file)) { + fs.rmSync(file); + } + } else if (fs.existsSync(file)) { + fs.copyFileSync(file, oldFile); + } else { + throw new Error("File not found: " + file); + } + console.log("patching", file); + lines = fs.readFileSync(oldFile, "utf-8").split("\n"); + currentLine = 0; + outLines = []; + fn(); + skipToEnd(); + fs.writeFileSync(file, outLines.join("\n")); +} +/** + * skip from currentLine until a line matches a condition + * update currentLine. Throws if not found. + * + * new current line will not be pushed, but skipped lines will + */ +const skipUntil = (matches: (line: string) => boolean) => { + for (; currentLine< lines.length; currentLine++) { + if (matches(lines[currentLine])) { + return; + } + outLines.push(lines[currentLine]); + } + throw new Error("Not found"); +} +const skipToEnd = () => { + outLines.push(...lines.slice(currentLine)); + currentLine = lines.length; +} +const addPatch = (content: string) => { + outLines.push(...content.split("\n").filter(Boolean).map(line => line.trimEnd())); +} + +patchFile("lib/monaco-editor/esm/vs/language/typescript/ts.worker.js", () => { + skipUntil(line => line.trim() === "// src/language/typescript/tsWorker.ts"); + skipUntil(line => line.trim().includes("class _TypeScriptWorker {")) + skipUntil(line => line.trim().startsWith("async provideInlayHints(")); + // add our function here + addPatch(` + async getEncodedSemanticClassifications(fileName, start, end) { + if (fileNameIsLib(fileName)) { return undefined }; + const span = { start, length: end - start }; + return this._languageService.getEncodedSemanticClassifications(fileName, span, "2020"); + } +`); +}); + +patchFile("lib/monaco-editor/monaco.d.ts", patchTypeScriptWorkerInterface); +patchFile("lib/monaco-editor/esm/vs/editor/editor.api.d.ts", patchTypeScriptWorkerInterface); + +function patchTypeScriptWorkerInterface() { + skipUntil(line => line.trim() === "export interface TypeScriptWorker {"); + skipUntil(line => line.trim().startsWith("provideInlayHints(")); + addPatch(`getEncodedSemanticClassifications(fileName: string, start: number, end: number): Promise<{spans: number[]}|undefined>;`); +} diff --git a/packages/monaco-editor-contrib/tsconfig.json b/packages/monaco-editor-contrib/tsconfig.json new file mode 100644 index 0000000..081c74d --- /dev/null +++ b/packages/monaco-editor-contrib/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + }, + "include": ["patch.ts"] +} diff --git a/packages/monaco-typescript-contrib/README.md b/packages/monaco-typescript-contrib/README.md new file mode 100644 index 0000000..41e7be4 --- /dev/null +++ b/packages/monaco-typescript-contrib/README.md @@ -0,0 +1,5 @@ +# monaco-typescript-contrib + +This is an experimental improved Monarch tokenizer for TypeScript + +## Token Classes diff --git a/packages/monaco-typescript-contrib/package.json b/packages/monaco-typescript-contrib/package.json new file mode 100644 index 0000000..7cc7471 --- /dev/null +++ b/packages/monaco-typescript-contrib/package.json @@ -0,0 +1,25 @@ +{ + "name": "@pistonite/monaco-typescript-contrib", + "private": true, + "version": "0.0.1", + "description": "TODO", + "homepage": "TODO", + "bugs": { + "url": "TODO" + }, + "license": "MIT", + "author": "Pistonight ", + "files": [ + "src/**/*" + ], + "exports": { + ".": "./src/index.ts" + }, + "todo.repository": { + "type": "git", + "url": "https://github.com" + }, + "devDependencies": { + "monaco-editor-contrib": "0.52.2" + } +} diff --git a/packages/monaco-typescript-contrib/src/index.ts b/packages/monaco-typescript-contrib/src/index.ts new file mode 100644 index 0000000..caf2cd7 --- /dev/null +++ b/packages/monaco-typescript-contrib/src/index.ts @@ -0,0 +1,16 @@ +import * as monaco from "monaco-editor-contrib"; +import { language } from "./language.ts"; +import { DocumentRangeSemanticTokensProviderAdapter } from "./semantic.ts"; + +export type Option = { + /** maximum source length to enable semantic highlighting */ + semanticTokensMaxLength?: number; +} + +export function patchMonacoTypeScript(options?: Option) { + monaco.languages.setMonarchTokensProvider("typescript", language); + monaco.languages.registerDocumentRangeSemanticTokensProvider( + "typescript", + new DocumentRangeSemanticTokensProviderAdapter(options?.semanticTokensMaxLength) + ); +} diff --git a/packages/monaco-typescript-contrib/src/language.ts b/packages/monaco-typescript-contrib/src/language.ts new file mode 100644 index 0000000..d767a87 --- /dev/null +++ b/packages/monaco-typescript-contrib/src/language.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as monaco from "monaco-editor-contrib/esm/vs/editor/editor.api.ts"; + +// @ts-ignore no types +import { language as original } from "monaco-editor-contrib/esm/vs/basic-languages/typescript/typescript.js"; + +export const language = { + ...original, + tokenizer: { + ...original.tokenizer, + common: [ + // New rules + [/(true|false)/, "constant.language.boolean"], + [/null/, "constant.language.null"], + [/undefined/, "constant.language.undefined"], + [/(this|super|self)/, "variable.language"], + // something that *could* be a function call/declaration + [/#?[a-z_$][\w$]*(?=(\s*\(|\s*<.*>\s*\(|\s*`))/, { + cases: { + '@keywords': "keyword", + '@default': "function", + } + }], + + // patch old rule + [ + /#?[a-z_$][\w$]*/, + { + cases: { + "@keywords": "keyword", + "@default": "variable" + } + } + ], + ...original.tokenizer.common.slice(1), + ] + } +}; diff --git a/packages/monaco-typescript-contrib/src/semantic.ts b/packages/monaco-typescript-contrib/src/semantic.ts new file mode 100644 index 0000000..162290b --- /dev/null +++ b/packages/monaco-typescript-contrib/src/semantic.ts @@ -0,0 +1,315 @@ +import * as monaco from "monaco-editor-contrib"; + +const legend: monaco.languages.SemanticTokensLegend = { + tokenTypes: [ + // 1 - Class + "type.class", + // 2 - Enum + "type.enum", + // 3 - Interface + "type.interface", + // 4 - Namespace + "type.namespace", + // 5 - TypeParameter + "type.parameter", + // 6 - Type + "type", + // 7 - Parameter + "variable.parameter", + // 8 - Variable, + "variable", + // 9 - EnumMember + "variable.other.enummember", + // 10 - Property + "variable", + // 11 - Function + "function", + // 12 - Member + "variable", + ], + tokenModifiers: [ + "declaration", + "static", + "async", + "readonly", + // "defaultLibrary" + "language", + "local", + ] +} + +const setTimeout = self.setTimeout; + +/** Per-model request for semantic tokens */ +type RangeSemanticTokensRequest = { + scheduled: false; +} | { + scheduled: true; + model: monaco.editor.ITextModel; + // merged range + range: monaco.Range; + // latest cancellation token + token: monaco.CancellationToken; + promise: Promise; + resolve: (value: monaco.languages.SemanticTokens | undefined) => void; + reject: (reason: unknown) => void; +}; +export class DocumentRangeSemanticTokensProviderAdapter + implements monaco.languages.DocumentRangeSemanticTokensProvider { + + private worker?: (...uris: monaco.Uri[]) => Promise; + + + constructor( + private maxLength: number = 50000, + private debounceInterval: number = 500, + ) { + } + + // --- batcher implementation --- + private requests: Map = new Map(); + + public provideDocumentRangeSemanticTokens( + model: monaco.editor.ITextModel, + range: monaco.Range, + token: monaco.CancellationToken): + Promise { + if (!this.shouldRun(model)) { + return Promise.resolve(undefined); + } + const resource = model.uri.toString(); + const request = this.requests.get(resource); + if (!request) { + // not currently running any request for this model, + // execute immediately and mark as running + this.requests.set(resource, {scheduled: false}); + return this.executeBatched(resource, model, range, token); + } + return this.updateRequest(request, model, resource, range, token); + } + + private shouldRun(model: monaco.editor.ITextModel): boolean { + if (this.maxLength > 0 && model.getValueLength() > this.maxLength) { + return false; + } + return true; + } + + private updateRequest( + request: RangeSemanticTokensRequest, + model: monaco.editor.ITextModel, + resource: string, + range: monaco.Range, + token: monaco.CancellationToken + ): Promise { + if (request.scheduled) { + // abandon old range, since it's probably out of view anyway + request.range = range; + request.token = token; + return request.promise; + } + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject= rej; + }); + this.requests.set(resource, { + scheduled: true, + model, + range, + token, + promise, + resolve: resolve!, + reject: reject! + }); + return promise; + } + + private onRequestFinished(resource: string) { + const request = this.requests.get(resource); + if (!request) { + return; + } + if (!request.scheduled) { + // delete the entry to signify that no current + // request is running for this model + this.requests.delete(resource); + return; + } + + this.requests.set(resource, {scheduled: false}); + + const { model, range, token, resolve, reject } = request; + this.executeBatched(resource, model, range, token).then(resolve, reject); + } + + // --- adapter implementation --- + + getLegend(): monaco.languages.SemanticTokensLegend { + return legend; + } + + async executeBatched( + resource: string, + model: monaco.editor.ITextModel, + range: monaco.Range, + token: monaco.CancellationToken): + Promise { + let isWaitingForWorker = false; + const cb = () => { + if (!isWaitingForWorker) { + this.onRequestFinished(resource); + return; + } + setTimeout(cb, this.debounceInterval); + }; + setTimeout(cb, this.debounceInterval); + const start = model.getOffsetAt({ + lineNumber: range.startLineNumber, + column: range.startColumn + }) + const end = model.getOffsetAt({ + lineNumber: range.endLineNumber, + column: range.endColumn + }) + const worker = await this.getWorker(model.uri); + // check after await + if (model.isDisposed() || token.isCancellationRequested) { + return undefined; + } + isWaitingForWorker = true; + const result = await worker.getEncodedSemanticClassifications(resource, start, end); + isWaitingForWorker = false; + // check after await + if (!result || model.isDisposed() || token.isCancellationRequested) { + return undefined; + } + const { spans } = result; + const data = this.convertTokens(model, spans ); + return { + data: new Uint32Array(data) + } + } + + private convertTokens(model: monaco.editor.ITextModel, inputs: number[]): number[] { + // inputs are triples: [start, length, type] + // outputs are 5-tuples: [deltaLine, deltaStart, length, tokenType, tokenModifiers] + const outputs = []; + let prevLine = 1; + let prevStart = 1; + + // since we only run this for the latest range that's requested, + // we should never have to worry about having too many tokens + // returned from the worker + for (let i = 0; i + 3 <= inputs.length; i += 3) { + const start = inputs[i]; + const length = inputs[i + 1]; + let modifier = inputs[i + 2]; + let type = modifier >> 8; + // type should be 1-indexed + if (!type || type > legend.tokenTypes.length) { + continue; + } + + // fix the type and modifiers to have better highlighting + + // readonly + lower bits (declaration, static, async) + if ((modifier & 0b1000) && (modifier & 0b111)) { + // only keep readonly, so less important + // modifiers don't take priority + modifier = 0b1000; + } + // special handling for property and member + if (type === 10 || type === 12) { + // ignore non-readonly modifiers + // for things like foo.bar(), we want to hightlight + // bar as a function instead of variable + if (!(modifier & 0b1000)) { + continue; + } + // only keep defaultLibrary on non-property/member + // this is for things like [].length, where length + // would be highlighted as a normal property, + // instead of the same as this, self, super, etc.. + modifier &= ~0b10000; + } + // offset by 1 + type--; + // only keep the bits of modifier that matters + modifier &= 0xff; + + const { startLineNumber, startColumn, endLineNumber, endColumn } = this._textSpanToRange( + model, + { start, length } + ); + if (startLineNumber === endLineNumber) { + const deltaLine = startLineNumber - prevLine; + const deltaStart = deltaLine === 0 ? startColumn - prevStart : startColumn - 1; + + // handy debug code since we can't inspect semantic tokens yet + // console.log({ + // value: model.getValueInRange({startLineNumber, startColumn, endLineNumber, endColumn}), + // type: legend.tokenTypes[type], + // modifier: modifier.toString(2) + // }) + + outputs.push(deltaLine, deltaStart, length, type, modifier); + prevStart = startColumn; + } else { + // token spanning multiple lines, convert it to separate entries + const firstStart = startColumn - 1; + const firstLength = model.getLineLength(startLineNumber) - firstStart; + const firstDeltaLine = startLineNumber - prevLine; + const firstDeltaStart = firstDeltaLine === 0 ? firstStart - prevStart : firstStart - 1; + outputs.push(firstDeltaLine, firstDeltaStart, firstLength, type, modifier); + + // middle full lines + for (let i = startLineNumber + 1; i < endLineNumber; i++) { + // delta line is always 1, start is always 0 + const length = model.getLineLength(i); + outputs.push(1, 0, length, type, modifier); + } + + // last line, if we are not ending at the start of the line + if (endColumn !== 1) { + const lastLength = endColumn - 1; + outputs.push(1, 0, lastLength, type, modifier); + } + prevStart = 1; + } + prevLine = endLineNumber; + } + + return outputs; + } + + // --- debug/utils --- can be removed when upstreaming the work + + // lazy get the worker, since typescript may not be loaded yet + private async getWorker(resource: monaco.Uri): Promise { + while (!this.worker) { + console.log("getting instance of TypeScript worker..."); + try { + this.worker = await monaco.languages.typescript.getTypeScriptWorker(); + if (!this.worker) { + throw new Error("getTypeScriptWorker returned undefined"); + } + break; + } catch (e) { + console.error("Failed to get worker", e); + console.warn("will try again in a bit. This should not happen when this is initialized as part of TS mode"); + await new Promise(r => setTimeout(r, 1000)); + } + } + return await this.worker(resource); + } + + private _textSpanToRange(model: monaco.editor.ITextModel, span: {start: number, length: number}): monaco.IRange { + let p1 = model.getPositionAt(span.start); + let p2 = model.getPositionAt(span.start + span.length); + let { lineNumber: startLineNumber, column: startColumn } = p1; + let { lineNumber: endLineNumber, column: endColumn } = p2; + return { startLineNumber, startColumn, endLineNumber, endColumn }; + } +} diff --git a/app/tsconfig.app.json b/packages/monaco-typescript-contrib/tsconfig.json similarity index 88% rename from app/tsconfig.app.json rename to packages/monaco-typescript-contrib/tsconfig.json index f0a2350..512058a 100644 --- a/app/tsconfig.app.json +++ b/packages/monaco-typescript-contrib/tsconfig.json @@ -12,13 +12,12 @@ "isolatedModules": true, "moduleDetection": "force", "noEmit": true, - "jsx": "react-jsx", /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, }, "include": ["src"] } diff --git a/packages/parser/Cargo.toml b/packages/parser/Cargo.toml new file mode 100644 index 0000000..8fed9e1 --- /dev/null +++ b/packages/parser/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "skybook-parser" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +derive_more = { version = "1.0.0", features = ["deref", "deref_mut"] } +teleparse = "0.0.5" +thiserror = "2.0.9" diff --git a/packages/parser/src/cir/item_meta.rs b/packages/parser/src/cir/item_meta.rs new file mode 100644 index 0000000..4968fb8 --- /dev/null +++ b/packages/parser/src/cir/item_meta.rs @@ -0,0 +1,324 @@ +use teleparse::{tp, Span}; + +use crate::error::{ErrorReport, Error}; +use crate::item_search::ItemResolver; +use crate::syn; +use crate::cir; + +use super::MetaParser; + +/// Item metadata used to select or specify item +#[derive(Debug, Default)] +pub struct ItemMeta { + /// The value of the item + /// + /// settable by: + /// - `life=100` -> 100 + /// - `value=100` -> 100 + /// - `durability=1` -> 100 + pub value: Option, + + /// If the item is equipped + /// + /// settable by `equip`, `equipped` + pub equip: Option, + + /// Settable by key `life_recover, hp, modpower` + pub life_recover: Option, + /// Settable by `time` + pub effect_duration: Option, + /// Settable by `price` (set), `modifier` (add) + pub sell_price: Option, + /// Settable by `effect` name + pub effect_id: Option, + /// Settable by `level` + pub effect_level: Option, + + /// Settable by `ingr` + pub ingredients: Vec, +} + +impl ItemMeta { + pub async fn parse(meta: &syn::ItemMeta, resolver: &R, errors: &mut Vec) -> ItemMeta { + let parser = Parser { + meta: ItemMeta::default(), + resolver, + }; + cir::parse_meta(meta, parser, errors).await + } +} + +struct Parser<'r, R: ItemResolver> { + meta: ItemMeta, + resolver: &'r R, +} + +impl MetaParser for Parser<'_, R> { + type Output = ItemMeta; + + async fn visit_start(&mut self, _meta: &syn::ItemMeta, _errors: &mut Vec) { + } + + async fn visit_entry(&mut self, span: Span, key: &tp::String, value: &tp::Option, errors: &mut Vec) { + let key_str = key.to_ascii_lowercase(); + match key_str.trim() { + "life" | "value" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.value = Some(x as i32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "durability" | "dura" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.value = Some((x * 100) as i32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "equip" | "equipped"=> { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Bool(x)) => { + self.meta.equip = Some(x); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "life_recover" | "hp" | "modpower" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.life_recover = Some(x as i32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "time" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.effect_duration = Some(x as i32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "price" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.sell_price = Some(x as i32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "modifier" | "modtype" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + // integer => same as price + self.meta.sell_price = Some(x as i32); + } + Ok(cir::MetaValue::String(x)) => { + // string modifier, parse it and add it + match parse_weapon_modifier_bits(&x) { + Some(m) => self.meta.sell_price = Some(self.meta.sell_price.unwrap_or_default() | m), + None => { + errors.push( + Error::InvalidWeaponModifier(x) + .spanned(value) + ); + } + } + } + Ok(mv) => { + errors.push( + Error::InvalidWeaponModifier(mv.to_string()) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "effect" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + // integer => set it without checking + self.meta.effect_id = Some(x as i32); + } + Ok(cir::MetaValue::String(x)) => { + // string modifier, parse it + match parse_cook_effect(&x) { + Some(m) => self.meta.effect_id = Some(m), + None => { + errors.push( + Error::InvalidCookEffect(x) + .spanned(value) + ); + } + } + } + Ok(mv) => { + errors.push( + Error::InvalidWeaponModifier(mv.to_string()) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "level" => { + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::Int(x)) => { + self.meta.effect_level = Some(x as f32); + } + Ok(cir::MetaValue::Float(x)) => { + self.meta.effect_level = Some(x as f32); + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + }, + "ingr" => { + if self.meta.ingredients.len() >= 5 { + errors.push( + Error::TooManyIngredients.spanned(value) + ); + return; + } + match cir::MetaValue::parse_option(value.as_ref()) { + Ok(cir::MetaValue::String(x)) => { + // currently we only support looking up by english + match self.resolver.resolve(&x).await { + Some(item) => { + self.meta.ingredients.push(item); + } + None => { + errors.push( + Error::InvalidItem(x) + .spanned(value) + ); + } + } + } + Ok(mv) => { + errors.push( + Error::InvalidMetaValue(key_str, mv) + .spanned(value) + ); + } + Err(e) => { + errors.push(e); + } + } + } + _ => { + errors.push( + Error::UnusedMetaKey(key_str).spanned_warning(&span) + ); + } + } + } + + async fn visit_end(&mut self, meta: &syn::ItemMeta, errors: &mut Vec) { + todo!() + } + + async fn finish(self) -> Self::Output { + todo!() + } +} + +fn parse_weapon_modifier_bits(value: &str) -> Option { + let value = value.replace("_", "").replace("-", "").replace(" ", "").to_ascii_lowercase(); + match value.trim() { + "attack" | "attackup" | "addpower" => Some(0x1), + "addpowerplus" => Some(0x80000001u32 as i32), + "durability" | "durabilityup" | "addlife" => Some(0x2), + "addlifeplus" => Some(0x80000002u32 as i32), + "critical" | "criticalhit" => Some(0x4), + "longthrow" | "throw" => Some(0x8), + "multishot" | "spreadfire" => Some(0x10), + "zoom" => Some(0x20), + "quickshot" | "rapidfire" => Some(0x40), + "surfmaster" | "surf" | "shieldsurf" | "shieldsurfup" | "surfup" => Some(0x80), + "guard" | "guardup" | "addguard" => Some(0x100), + "addguardplus" => Some(0x80000100u32 as i32), + "plus" | "yellow" => Some(0x80000000u32 as i32), + _ => None, + } +} + +fn parse_cook_effect(value: &str) -> Option { + let value = value.replace("_", "").replace("-", "").replace(" ", "").to_ascii_lowercase(); + match value.trim() { + "hearty" | "lifemaxup" => Some(2), + "chilly" | "chill" | "resisthot"=> Some(4), + "spicy" | "resistcold" => Some(5), + "electro" | "resistelectric" => Some(6), + "mighty" | "attack" | "attackup" => Some(10), + "tough" | "defense" | "defenseup" => Some(11), + "sneaky" | "quiet" | "stealth" | "stealthup" | "quietness" => Some(12), + "speed" | "speedup" | "allspeed" | "movingspeed" => Some(13), + "energizing" | "stamina" | "staminaup" | "stam" | "stamup" | "gutsrecover" | "guts" => Some(14), + "enduring" | "endura" | "endur" | "exgutsmaxup" | "exguts" => Some(15), + "fire" | "fireproof" | "resistflame" | "resistfire" => Some(16), + _ => None, + } +} diff --git a/packages/parser/src/cir/mod.rs b/packages/parser/src/cir/mod.rs new file mode 100644 index 0000000..a8655a2 --- /dev/null +++ b/packages/parser/src/cir/mod.rs @@ -0,0 +1,118 @@ +use teleparse::{tp, Span, ToSpan}; + +use crate::error::Error; +use crate::syn; +use crate::{error::ErrorReport}; + +mod item_meta; + + +pub trait MetaParser { + type Output; + + async fn visit_start(&mut self, meta: &syn::ItemMeta, errors: &mut Vec); + async fn visit_entry(&mut self, span: Span, key: &tp::String, value: &tp::Option, errors: &mut Vec); + async fn visit_end(&mut self, meta: &syn::ItemMeta, errors: &mut Vec); + async fn finish(self) -> Self::Output; +} + +pub async fn parse_meta(meta: &syn::ItemMeta, mut parser: T, errors: &mut Vec) -> T::Output { + parser.visit_start(meta, errors).await; + let span = meta.span(); + for entry in &meta.entries { + parser.visit_entry(span, &entry.key, &entry.value, errors).await; + } + parser.visit_end(meta, errors).await; + parser.finish().await +} + +#[derive(Debug, Clone)] +pub enum MetaValue { + Bool(bool), + Int(i64), + Float(f64), + String(String), +} + +impl std::fmt::Display for MetaValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MetaValue::Bool(b) => write!(f, "{}", b), + MetaValue::Int(i) => write!(f, "{}", i), + MetaValue::Float(fl) => write!(f, "{}", fl), + MetaValue::String(s) => write!(f, "{}", s), + } + } +} + +impl MetaValue { + pub fn parse_option(value: Option<&syn::ItemMetaValue>) -> Result { + match value { + Some(v) => Ok(Self::parse(&v.value)?), + None => Ok(Self::Bool(true)), + } + } + pub fn parse(value: &syn::MetaValueLiteral) -> Result { + match value { + syn::MetaValueLiteral::Word(x) => { + let s = x.trim(); + match s { + "true" => Ok(Self::Bool(true)), + "false" => Ok(Self::Bool(false)), + _ => Ok(Self::String(s.to_string())), + } + } + syn::MetaValueLiteral::Number(x) => { + let int_part: &str = &*x.int_part; + let int_part = match int_part.strip_prefix("0x") { + Some(rest) => i64::from_str_radix(rest, 16) + .map_err(|_| { + Error::IntFormat(x.int_part.to_string()).spanned(x) + })?, + + None => int_part.parse() + .map_err(|_| { + Error::IntFormat(x.int_part.to_string()).spanned(x) + })? + }; + let float_part = match &*x.float_part { + Some(fp) => fp, + None => return Ok(Self::Int(int_part)), + }; + let decimal_part = match &*float_part.1 { + Some(dp) => dp, + // Integer followed by dot, like 3. + None => return Ok(Self::Float(int_part as f64)), + }; + let decimal_str: &str = &*decimal_part; + let decimal_num = match decimal_part.strip_prefix("0x") { + Some(_) => { + // float part can't be hex + return Err( + Error::FloatFormat(format!("{}.{}", int_part, decimal_str)).spanned(x) + ) + } + + None => decimal_part.parse::() + .map_err(|_| { + Error::FloatFormat(format!("{}.{}", int_part, decimal_str)).spanned(x) + })? + }; + // float part can't be negative + if decimal_num < 0 { + return Err( + Error::FloatFormat(format!("{}.{}", int_part, decimal_str)).spanned(x) + ) + } + let full_str = format!("{}.{}", int_part, decimal_str); + let value = full_str.parse::() + .map_err(|_| { + Error::FloatFormat(format!("{}.{}", int_part, decimal_str)).spanned(x) + })?; + return Ok(Self::Float(value)); + } + } + + } +} + diff --git a/packages/parser/src/error.rs b/packages/parser/src/error.rs new file mode 100644 index 0000000..de906a0 --- /dev/null +++ b/packages/parser/src/error.rs @@ -0,0 +1,53 @@ +use teleparse::ToSpan; + +use crate::cir; + + +pub struct ErrorReport { + pub span: (usize, usize), + pub is_warning: bool, + pub error: Error, +} + +impl ErrorReport { + pub fn spanned(t: &T, error: Error) -> Self { + let span = t.span(); + Self { + span: (span.lo, span.hi), + is_warning: false, + error, + } + } +} + +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + #[error("failed to resolve item: {0}")] + InvalidItem(String), + #[error("invalid integer format: {0}")] + IntFormat(String), + #[error("invalid number format: {0}")] + FloatFormat(String), + #[error("unused meta key: {0}")] + UnusedMetaKey(String), + #[error("key `{0}` has invalid value: {0}")] + InvalidMetaValue(String, cir::MetaValue), + #[error("invalid weapon modifier: {0}")] + InvalidWeaponModifier(String), + #[error("invalid cook effect: {0}")] + InvalidCookEffect(String), + #[error("item has too many ingredients (max 5)")] + TooManyIngredients, +} + +impl Error { + pub fn spanned(self, t: &T) -> ErrorReport { + ErrorReport::spanned(t, self) + } + + pub fn spanned_warning(self, t: &T) -> ErrorReport { + let mut report = ErrorReport::spanned(t, self); + report.is_warning = true; + report + } +} diff --git a/packages/parser/src/item_search.rs b/packages/parser/src/item_search.rs new file mode 100644 index 0000000..1ee1285 --- /dev/null +++ b/packages/parser/src/item_search.rs @@ -0,0 +1,12 @@ + +pub trait ItemResolver { + type Future: std::future::Future + Send + 'static; + + /// Resolve an item to its actor name + fn resolve(&self, word: &str) -> Self::Future>; + + /// Resolve a quote item word "like this" to its actor name + fn resolve_quoted(&self, word: &str) -> Self::Future>; + + +} diff --git a/packages/parser/src/lib.rs b/packages/parser/src/lib.rs new file mode 100644 index 0000000..9dbaee7 --- /dev/null +++ b/packages/parser/src/lib.rs @@ -0,0 +1,12 @@ + +/// Command syntax +mod syn; +/// Command intermediate representation +mod cir; + +mod error; +mod item_search; + +pub fn test_message(n: u64) -> String { + format!("Hello from Rust! You passed in {}", n) +} diff --git a/packages/parser/src/syn/category.rs b/packages/parser/src/syn/category.rs new file mode 100644 index 0000000..6322560 --- /dev/null +++ b/packages/parser/src/syn/category.rs @@ -0,0 +1,72 @@ +use teleparse::derive_syntax; + +use super::token::{KwArmor, KwArmors, KwBow, KwBows, KwFood, KwFoods, KwKeyItem, KwKeyItems, KwMaterial, KwMaterials, KwShield, KwShields, KwWeapon, KwWeapons}; + +/// Category specifier +#[derive_syntax] +#[derive(Debug)] +pub enum Category { + Weapon(CatWeapon), + Bow(CatBow), + Shield(CatShield), + Armor(CatArmor), + Material(CatMaterial), + Food(CatFood), + KeyItem(CatKeyItem), +} + +/// The "weapon" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatWeapon { + Singular(KwWeapon), + Plural(KwWeapons), +} + +/// The "bow" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatBow { + Singular(KwBow), + Plural(KwBows), +} + +/// The "shield" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatShield { + Singular(KwShield), + Plural(KwShields), +} + +/// The "armor" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatArmor { + Singular(KwArmor), + Plural(KwArmors), +} + +/// The "material" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatMaterial { + Singular(KwMaterial), + Plural(KwMaterials) +} + +/// The "food" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatFood { + Singular(KwFood), + Plural(KwFoods) +} + +/// The "key item" tab/category +#[derive_syntax] +#[derive(Debug)] +pub enum CatKeyItem { + Singular(KwKeyItem), + Plural(KwKeyItems), +} diff --git a/packages/parser/src/syn/command.rs b/packages/parser/src/syn/command.rs new file mode 100644 index 0000000..76d05de --- /dev/null +++ b/packages/parser/src/syn/command.rs @@ -0,0 +1,342 @@ +//! Syntax for commands + +use teleparse::{derive_syntax, tp}; + +use super::token::{KwGet, KwBuy, KwHoldAttach +}; +use super::item_list::{ItemListFinite, ItemListConstrained}; +use super::{Category, ItemMeta, ItemWithSlot, ItemWithSlotOrCategory, KwBake, KwBoil, KwCloseGame, KwCloseInventory, KwCook, KwDestroy, KwDnp, KwDrop, KwEat, KwEntangle, KwEnter, KwEquip, KwExit, KwFreeze, KwHold, KwHoldSmuggle, KwLeave, KwNewGame, KwOpenInventory, KwPickUp, KwReload, KwRoast, KwSave, KwSaveAs, KwSell, KwShoot, KwSort, KwTalkTo, KwUnequip, KwUnhold, KwUntalk, KwUse, TimesClause, Word}; + +#[derive_syntax] +#[derive(Debug)] +pub enum Command { + // ==== adding items ==== + + /// `get ITEMS` + Get(CmdGet), + /// `buy ITEMS` + Buy(CmdBuy), + /// `pick-up ITEMS` + PickUp(CmdPickup), + + // ==== holding items ==== + + /// `hold ITEMS` + Hold(CmdHold), + /// `hold-smuggle ITEMS` + HoldSmuggle(CmdHoldSmuggle), + /// `hold-attach ITEMS` + HoldAttach(CmdHoldAttach), + /// `unhold` + Unhold(KwUnhold), + /// `drop` or `drop ITEMS` + Drop(CmdDrop), + /// `dnp ITEMS` + Dnp(CmdDnp), + /// `cook` or `cook ITEMS` + Cook(CmdCook), + + // ==== removing items ==== + + /// `eat ITEMS` + Eat(CmdEat), + /// `sell ITEMS` + Sell(CmdSell), + + // ==== equipments ==== + + /// `equip ITEM` + Equip(CmdEquip), + /// `unequip ITEM` or `unequip CATEGORY` + UnEquip(CmdUnequip), + /// `use CATEGORY X times` + Use(CmdUse), + /// `shoot X times` + Shoot(CmdShoot), + + // ==== overworld ==== + + /// `roast ITEMS` + Roast(CmdRoast), + /// `bake ITEMS` - same as roast + Bake(CmdBake), + /// `boil ITEMS` - same as roast except for eggs + Boil(CmdBoil), + /// `freeze ITEMS` + Freeze(CmdFreeze), + /// `destroy ITEMS` + Destroy(CmdDestroy), + + // ==== inventory ==== + + /// `sort CATEGORY` + Sort(CmdSort), + /// `entangle CATEGORY [tab=X, rol=R, col=C]` + Entangle(CmdEntangle), + + // ==== saves ==== + + /// `save` + Save(KwSave), + /// `save-as NAME` + SaveAs(CmdSaveAs), + /// `reload` or `reload NAME` + Reload(CmdReload), + /// `close-game` + CloseGame(KwCloseGame), + /// `new-game` + NewGame(KwNewGame), + + // ==== scopes ==== + OpenInventory(KwOpenInventory), + CloseInventory(KwCloseInventory), + TalkTo(KwTalkTo), + Untalk(KwUntalk), + + // ==== trials ==== + + /// `enter TRIAL` + Enter(CmdEnter), + /// `exit` - exit current trial + Exit(KwExit), + /// `leave` - leave current trial without clearing it + Leave(KwLeave), + +} + +/// `get ITEMS` - items come from the area +#[derive_syntax] +#[derive(Debug)] +pub struct CmdGet { + pub lit: KwGet, + pub items: ItemListFinite, +} + +/// `buy ITEMS` - items come from shop in the area +#[derive_syntax] +#[derive(Debug)] +pub struct CmdBuy { + pub lit: KwBuy, + pub items: ItemListFinite, +} + +/// `pick-up ITEMS` - items come from ground +#[derive_syntax] +#[derive(Debug)] +pub struct CmdPickup { + pub lit: KwPickUp, + pub items: ItemListConstrained, +} + +/// `hold ITEMS` - items come from inventory +#[derive_syntax] +#[derive(Debug)] +pub struct CmdHold { + pub lit: KwHold, + pub items: ItemListConstrained, +} + +/// `hold-smuggle ITEMS` - items come from inventory, will not hold in overworld +#[derive_syntax] +#[derive(Debug)] +pub struct CmdHoldSmuggle { + pub lit: KwHoldSmuggle, + pub items: ItemListConstrained, +} + +/// `hold-attach ITEMS` - items come from inventory, +/// dropping happens after returning to overworld scope +#[derive_syntax] +#[derive(Debug)] +pub struct CmdHoldAttach { + pub lit: KwHoldAttach, + pub items: ItemListConstrained, +} + +/// `drop` or `drop ITEMS` +/// +/// `drop ITEMS` is a shorthand, which holds the items, then drop them. +/// Cannot perform if already holding items. The exception is if the +/// item has "drop" prompt instead of "hold" prompt (equipments), +/// it will just drop the item instead +#[derive_syntax] +#[derive(Debug)] +pub struct CmdDrop { + pub lit: KwDrop, + pub items: tp::Option, +} + +/// `dnp ITEMS` - shorthand for `drop ITEMS` and `pick-up ITEMS` +#[derive_syntax] +#[derive(Debug)] +pub struct CmdDnp { + pub lit: KwDnp, + pub items: ItemListConstrained, +} + +/// `cook` or `cook ITEMS` - cook items in inventory +/// +/// `cook ITEMS` is a shorthand, which holds the items, then cook them. +#[derive_syntax] +#[derive(Debug)] +pub struct CmdCook { + pub lit: KwCook, + pub items: tp::Option, +} + +/// `eat ITEMS` - execute eat prompt on targeted items. +/// The number is the times to eat the item. +#[derive_syntax] +#[derive(Debug)] +pub struct CmdEat { + pub lit: KwEat, + pub items: ItemListConstrained, +} + +/// `sell ITEMS` - sell items to shop in the area. +#[derive_syntax] +#[derive(Debug)] +pub struct CmdSell { + pub lit: KwSell, + pub items: ItemListConstrained, +} + +/// `equip ITEM` - equip one thing +#[derive_syntax] +#[derive(Debug)] +pub struct CmdEquip { + pub lit: KwEquip, + pub items: ItemWithSlot, +} + +/// `unequip ITEM` - unequip one thing, or (all items) in one category +#[derive_syntax] +#[derive(Debug)] +pub struct CmdUnequip { + pub lit: KwUnequip, + pub items: ItemWithSlotOrCategory, +} + +/// `use CATEGORY X times` - use the item +#[derive_syntax] +#[derive(Debug)] +pub struct CmdUse { + pub lit: KwUse, + pub category: Category, + pub times: TimesClause, +} + +/// `shoot X times` is shorthand for `use bow X times` +#[derive_syntax] +#[derive(Debug)] +pub struct CmdShoot { + pub lit: KwShoot, + pub times: TimesClause, +} + +/// `roast ITEMS` - roast items on the ground or in inventory +/// +/// Items on the ground has priority, if there are not enough, +/// but there are items in inventory, then `drop ITEMS` will be +/// used to drop the items on the ground. +#[derive_syntax] +#[derive(Debug)] +pub struct CmdRoast { + pub lit: KwRoast, + pub items: ItemListConstrained, +} + +/// Alias for `roast` +#[derive_syntax] +#[derive(Debug)] +pub struct CmdBake { + pub lit: KwBake, + pub items: ItemListConstrained, +} + +/// Same as `roast`, except for eggs, where you will get boiled eggs +/// instead of campfire eggs +#[derive_syntax] +#[derive(Debug)] +pub struct CmdBoil { + pub lit: KwBoil, + pub items: ItemListConstrained, +} + +/// Similar to `roast`, but get the frozen variants +#[derive_syntax] +#[derive(Debug)] +pub struct CmdFreeze { + pub lit: KwFreeze, + pub items: ItemListConstrained, +} + +/// Destroy items on the ground +/// +/// This will just delete it from simulation. In the game, +/// there are various way to do it: throw it into the sea, +/// throw it into the lava, bomb it, etc. +/// +/// If not enough items are on the ground, items from the inventory +/// is used +#[derive_syntax] +#[derive(Debug)] +pub struct CmdDestroy { + pub lit: KwDestroy, + pub items: ItemListConstrained, +} + +/// `sort CATEGORY` - sort the category +#[derive_syntax] +#[derive(Debug)] +pub struct CmdSort { + pub lit: KwSort, + pub category: Category, +} + +/// `entangle CATEGORY [tab=X, rol=R, col=C]` - activate prompt entanglement +#[derive_syntax] +#[derive(Debug)] +pub struct CmdEntangle { + pub lit: KwEntangle, + pub category: Category, + pub meta: tp::Option +} + +/// `save-as NAME` - save the game to a named slot +#[derive_syntax] +#[derive(Debug)] +pub struct CmdSaveAs { + pub lit: KwSaveAs, + pub name: tp::Vec, +} + +/// `reload` - reload the game from manual or named save slot +/// +/// This can also be used to start the game, then reload a save +#[derive_syntax] +#[derive(Debug)] +pub struct CmdReload { + pub lit: KwReload, + pub name: tp::Vec, +} + +/// `enter TRIAL` - enter a trial +/// +/// # Trials: +/// - eventide +/// - tots/trial of the sword +/// - beginning trial (when you clear a TOTS for the first time, MS will be automatically upgraded, +/// which constitutes a gamedata sync +/// - middle trial +/// - final trial +/// - thunderblight refight (when you clear a refight for the first time, ability will be upgraded) +/// - windblight refight +/// - waterblight refight +/// - fireblight refight +#[derive_syntax] +#[derive(Debug)] +pub struct CmdEnter { + pub lit: KwEnter, + pub trial: tp::Vec, +} diff --git a/packages/parser/src/syn/item.rs b/packages/parser/src/syn/item.rs new file mode 100644 index 0000000..bee2a05 --- /dev/null +++ b/packages/parser/src/syn/item.rs @@ -0,0 +1,127 @@ +//! Base syntax for specifying an item + +use teleparse::{derive_syntax, tp}; + +use super::token::{ + AngledWord, ColonOrEqual, + NumOrAll, NumOrInfinite, Number, + QuotedWord, SymComma, SymLBracket, + SymRBracket, Word, MetaValueLiteral, KwAll, SlotClause}; + +use super::category::Category; + +/// Syntax for an item prefixed with a numeric amount +#[derive_syntax] +#[derive(Debug)] +pub struct NumberedItem { + #[teleparse(semantic(Amount))] + pub num: Number, + pub item: Item, +} + +/// Syntax for an item prefixed with an amount or "all" +#[derive_syntax] +#[derive(Debug)] +pub enum NumberedOrAllItemOrCategory { + Numbered(NumberedItem), + All(AllItemOrCategory), +} + +/// Syntax for an item prefixed with "all" +#[derive_syntax] +#[derive(Debug)] +pub struct AllItemOrCategory { + #[teleparse(semantic(Amount))] + pub all: KwAll, + pub items: ItemOrCategory, +} + +/// Syntax for an item or a category +#[derive_syntax] +#[derive(Debug)] +pub enum ItemOrCategory { + Item(Item), + Category(Category), +} + +/// Syntax for specifying a single item with a slot +#[derive_syntax] +#[derive(Debug)] +pub struct ItemWithSlot { + pub item: Item, + pub slot: tp::Option, +} + +/// Syntax for an item with a slot or a category +#[derive_syntax] +#[derive(Debug)] +pub enum ItemWithSlotOrCategory { + Item(ItemWithSlot), + Category(Category), +} + +/// Syntax for an item prefixed with an amount or "infinite" +#[derive_syntax] +#[derive(Debug)] +pub struct NumberedOrInfiniteItem { + #[teleparse(semantic(Amount))] + pub num: NumOrInfinite, + pub item: Item, +} + +/// Syntax for an item +/// +/// # Example +/// - `item` +/// - `item[meta]` +/// - `"item"` +/// - `` +#[derive_syntax] +#[derive(Debug)] +pub struct Item { + #[teleparse(semantic(Name))] + pub name: ItemName, + pub meta: tp::Option, +} + +/// Syntax for the name of an item, like `item`, `"item"`, or `` +#[derive_syntax] +#[derive(Debug)] +pub enum ItemName { + /// Using `-` or `_` separated word to search item by English name + Word(Word), + /// Use quoted value to search by name in any language + Quoted(QuotedWord), + /// Use angle brackets to use the literal as the actor name + /// e.g. `` + Angle(AngledWord), +} + +/// Syntax for the metadata specifier for an item, e.g. `[key1:value1, key2=value2, key3]` +#[derive_syntax] +#[derive(Debug)] +pub struct ItemMeta { + pub open: SymLBracket, + pub entries: tp::Punct, + pub close: SymRBracket, +} + +/// A key-value pair in an item's metadata specifier +#[derive_syntax] +#[derive(Debug)] +pub struct ItemMetaKeyValue { + /// The key of the key-value pair + #[teleparse(semantic(Variable))] + pub key: tp::String, + pub value: tp::Option +} + +/// Value after the key in an item's metadata specifier +#[derive_syntax] +#[derive(Debug)] +pub struct ItemMetaValue { + /// The seperator between the key and value + pub sep: ColonOrEqual, + /// The value of the key-value pair + pub value: MetaValueLiteral, +} diff --git a/packages/parser/src/syn/item_list.rs b/packages/parser/src/syn/item_list.rs new file mode 100644 index 0000000..453af8a --- /dev/null +++ b/packages/parser/src/syn/item_list.rs @@ -0,0 +1,51 @@ +//! Syntax for specifying a list of items + +use teleparse::{derive_syntax, tp}; + +use super::item::{Item, ItemWithSlot, NumberedItem, NumberedOrInfiniteItem, NumberedOrAllItemOrCategory}; +use super::token::SlotClause; + +/// Specifying an unconstrained, finite list of items +/// +/// This is usually used for adding items +#[derive_syntax] +#[derive(Debug)] +pub enum ItemListFinite { + /// Single item, e.g. `apple` + Single(Item), + /// multiple items with amounts, e.g. `5 apples 3 royal_claymore` + List(tp::Nev), +} + +/// Specifying an unconstrained list of items that allows +/// an infinite amount of items +#[derive_syntax] +#[derive(Debug)] +pub enum ItemListInfinite { + /// Single item, e.g. `apple` + Single(Item), + /// multiple items with amounts, e.g. `5 apples infinite royal_claymore` + List(tp::Nev), +} + +/// Specifying items from a contrained list +/// +/// This is usually used for selecting items from a list (for example, +/// for removal) +#[derive_syntax] +#[derive(Debug)] +pub enum ItemListConstrained { + /// Single item, e.g. `apple :from slot 3` + Single(ItemWithSlot), + /// multiple items with amounts, e.g. `5 apples 3 royal_claymore :from slot 3` + List(ItemListWithSlot), +} + + +/// Syntax for specifying a list of items with a slot +#[derive_syntax] +#[derive(Debug)] +pub struct ItemListWithSlot { + pub items: tp::Nev, + pub slot: tp::Option, +} diff --git a/packages/parser/src/syn/mod.rs b/packages/parser/src/syn/mod.rs new file mode 100644 index 0000000..7e15c21 --- /dev/null +++ b/packages/parser/src/syn/mod.rs @@ -0,0 +1,31 @@ +use teleparse::{derive_syntax, tp}; + +mod token; +pub use token::*; + +mod item; +pub use item::*; + +mod item_list; +pub use item_list::*; + +mod command; +pub use command::*; + +mod category; +pub use category::*; + +#[derive_syntax] +#[teleparse(root)] +#[derive(Debug)] +pub struct Script { + pub stmts: tp::Loop, +} + +#[derive_syntax] +#[derive(Debug)] +pub struct Statement { + pub cmd: Command, + pub semi: tp::Option, +} + diff --git a/packages/parser/src/syn/token.rs b/packages/parser/src/syn/token.rs new file mode 100644 index 0000000..56aa047 --- /dev/null +++ b/packages/parser/src/syn/token.rs @@ -0,0 +1,214 @@ + +use derive_more::derive::{Deref, DerefMut}; +use teleparse::{derive_lexicon, derive_syntax, tp}; + +/// Token type +#[derive_lexicon] +#[teleparse(ignore(r"\s+", r"//.*\n", r"#.*\n"))] +pub enum TT { + #[teleparse(terminal( + SymLAngle = "<", + SymRAngle = ">", + SymLParen = "(", + SymRParen = ")", + SymLBracket = "[", + SymRBracket = "]", + SymLBrace = "{", + SymRBrace = "}", + SymEqual = "=", + SymColon = ":", + SymComma = ",", + SymSemi = ";", + SymQuote = "\"", + SymPeriod = ".", + ))] + Symbol, + + #[teleparse(regex(r"((-)?\d(_?\d)*)|(0x[\da-fA-F](_?[\da-fA-F])*)"), terminal(SymNumber))] + Number, + + #[teleparse(terminal( + // KwInit = "init", + // CmdInitGdt = "init-gdt", + // + KwGet = "get", + KwBuy = "buy", + + KwHold = "hold", + KwUnhold = "unhold", + KwHoldSmuggle = "hold-smuggle", + KwHoldAttach = "hold-attach", + KwDrop = "drop", + KwDnp = "dnp", + KwPickUp = "pick-up", + KwCook = "cook", + + KwEat = "eat", + KwSell = "sell", + + KwEquip = "equip", + KwUnequip = "unequip", + KwShoot = "shoot", + KwUse = "use", + + KwRoast = "roast", + KwBake = "bake", + KwBoil = "boil", + KwFreeze = "freeze", + KwDestroy = "destroy", + + KwSort = "sort", + KwEntangle = "entangle", + + KwSave = "save", + KwSaveAs = "save-as", + KwReload = "reload", + KwCloseGame = "close-game", + KwNewGame = "new-game", + + KwOpenInventory = "open-inventory", + KwCloseInventory = "close-inventory", + KwTalkTo = "talk-to", + KwUntalk = "untalk", + + KwEnter = "enter", + KwExit = "exit", + KwLeave = "leave", + + // reserved + + KwGoto = "go-to", + ))] + Command, + + #[teleparse(terminal( + KwAll = "all", + KwInfinite = "infinite", + KwWeapon = "weapon", + KwWeapons = "weapons", + KwBow = "bow", + KwBows = "bows", + KwShield = "shield", + KwShields = "shields", + KwArmor = "armor", + KwArmors = "armors", + KwMaterial = "material", + KwMaterials = "materials", + KwFood = "food", + KwFoods = "foods", + KwKeyItem = "key-item", + KwKeyItems = "key-items", + KwTime = "time", + KwTimes = "times", + ))] + Keyword, + + #[teleparse(regex(r"[_a-zA-Z][-0-9a-zA-Z_]*"), terminal(Word))] + Word, + + #[teleparse(regex(r#""[^"]*""#), terminal(QuotedWord))] + QuotedWord, + + Variable, + Name, + Type, + + Amount, + + SuperCommand, + Annotation, +} +#[derive_syntax] +#[derive(Debug, Deref, DerefMut)] +pub struct Number(pub tp::String); + +/// A word surrounded by angle brackets, e.g. `` +#[derive_syntax] +#[derive(Debug)] +pub struct AngledWord { + /// The opening angle bracket + pub open: SymLAngle, + /// The word inside the angle brackets + pub name: Word, + /// The closing angle bracket + pub close: SymRAngle, +} + +#[derive_syntax] +#[derive(Debug)] +pub enum MetaValueLiteral { + /// A string literal - could be true/false or a string + Word(tp::String>), + /// A numeric literal + #[teleparse(semantic(Number))] + Number(MetaValueNumber), +} + +#[derive_syntax] +#[derive(Debug)] +pub struct MetaValueNumber { + pub int_part: Number, + pub float_part: tp::Option<(SymPeriod, tp::Option)>, +} + +#[derive_syntax] +#[derive(Debug)] +pub struct SymMinus { + #[teleparse(literal("-"))] + pub minus: Word, +} + +/// A number or the string "all" +#[derive_syntax] +#[derive(Debug)] +pub enum NumOrAll { + All(KwAll), + Number(Number), +} + +/// A number or the string "infinite" +#[derive_syntax] +#[derive(Debug)] +pub enum NumOrInfinite { + Infinite(KwInfinite), + Number(Number), +} + +/// Colon or equal as separator +#[derive_syntax] +#[derive(Debug)] +pub enum ColonOrEqual { + Colon(SymColon), + Equal(SymEqual), +} + + +/// Syntax for specifying a slot (:from slot X, :in slot X, :at slot X) +#[derive_syntax] +#[derive(Debug)] +pub struct SlotClause { + pub colon: SymColon, + #[teleparse(literal("from"), + literial("in"), + literial("at"), + semantic(Keyword))] + pub kw: Word, + #[teleparse(literal("slot"), semantic(Keyword))] + pub kw_slot: Word, + + pub idx: Number, +} + +#[derive_syntax] +#[derive(Debug)] +pub struct TimesClause { + pub times: Number, + pub kw: KwTimes, +} + +#[derive_syntax] +#[derive(Debug)] +pub enum Time { + Singular(KwTime), + Plural(KwTimes), +} diff --git a/packages/research-data/.gitignore b/packages/research-data/.gitignore new file mode 100644 index 0000000..269dbba --- /dev/null +++ b/packages/research-data/.gitignore @@ -0,0 +1,2 @@ +/data +/output diff --git a/packages/research-data/README.md b/packages/research-data/README.md new file mode 100644 index 0000000..fc8ea75 --- /dev/null +++ b/packages/research-data/README.md @@ -0,0 +1,4 @@ +# skybook-actor-data + +This is the central location where data are generated from either +publicly available locations or from the game directly diff --git a/packages/research-data/Taskfile.yml b/packages/research-data/Taskfile.yml new file mode 100644 index 0000000..5e3f5fb --- /dev/null +++ b/packages/research-data/Taskfile.yml @@ -0,0 +1,7 @@ +version: '3' + +tasks: + generate-data: + aliases: [gd] + cmds: + - python bin/generate.py diff --git a/packages/research-data/bin/generate-localization.py b/packages/research-data/bin/generate-localization.py new file mode 100644 index 0000000..2f21125 --- /dev/null +++ b/packages/research-data/bin/generate-localization.py @@ -0,0 +1,150 @@ + +import yaml +import os +import multiprocessing +import shutil + +LOCALE_MAP = { + "en-US": "USen", + "ja-JP": "JPja", + "de-DE": "EUde", + "es-ES": "EUes", + "it-IT": "EUit", + "fr-FR": "EUfr", + "ru-RU": "EUru", + "zh-CN": "CNzh", + "zh-TW": "TWzh", + "ko-KR": "KRko", + "nl-NL": "EUnl", +} + +def main(): + home = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + actor_dir = os.path.join(home, "data", "Actor") + actor_files = [os.path.join(actor_dir, f) for f in os.listdir(actor_dir) ] + cook_effect_dir = os.path.join(home, "data", "CookEffect") + cook_effect_files = [os.path.join(cook_effect_dir, f) for f in os.listdir(cook_effect_dir) ] + special_status_dir = os.path.join(home, "data", "SpecialStatus") + special_status_files = [os.path.join(special_status_dir, f) for f in os.listdir(special_status_dir) ] + + data = {} + for locale in LOCALE_MAP: + data[locale] = {} + + with multiprocessing.Pool() as pool: + print("loading actor files...") + for result in pool.imap_unordered(load_entries_for_actor, actor_files): + if result: + for locale in result: + data[locale].update(result[locale]) + print("loading cook effect files...") + for result in pool.imap_unordered(load_entries_for_cook_effect, cook_effect_files): + if result: + for locale in result: + data[locale].update(result[locale]) + print("loading special status files...") + for result in pool.imap_unordered(load_entries_for_special_status, special_status_files): + if result: + for locale in result: + data[locale].update(result[locale]) + + output_dir = os.path.join(os.path.dirname(home), "localization", "src", "generated") + if os.path.exists(output_dir): + shutil.rmtree(output_dir) + os.makedirs(output_dir) + + for locale in data: + print(f"writing {locale}... ({len(data[locale])})") + output_file = os.path.join(output_dir, f"{locale}.yaml") + with open(output_file, "w", encoding="utf-8", newline="\n") as f: + yaml.dump(data[locale], f, sort_keys=True) + + +def load_entries_for_actor(actor_file) -> dict[str, dict[str, str]] | None: + """Load l10n entries from Actor/*.yaml""" + + with open(actor_file, "r", encoding="utf-8") as f: + actor = yaml.safe_load(f) + l10n = actor["localization"] + if not l10n: + return None + data = {} + for locale in LOCALE_MAP: + # name, replace {effect} with the attributed one + # e.g. feminine, masculine, neuter, plural + name = l10n[locale]["name"]["text"] + name_attr = l10n[locale]["name"]["attr"] + if name_attr: + name = name.replace("{{effect}}", "{{effect_"+name_attr+"}}") + desc = l10n[locale]["desc"] + album_desc = l10n[locale]["album_desc"] + # use album desc if desc is not provided + if not desc and album_desc: + desc = album_desc + + data[locale] = { + f"actor.{actor["actor"]}.name": name, + } + # not all actors have description + if desc: + data[locale][f"actor.{actor["actor"]}.desc"] = desc + return data + +def load_entries_for_cook_effect(cook_effect_file) -> dict[str, dict[str, str]] | None: + """Load l10n entries from CookEffect/*.yaml""" + + with open(cook_effect_file, "r", encoding="utf-8") as f: + cook_effect = yaml.safe_load(f) + l10n = cook_effect["localization"] + if not l10n: + return None + data = {} + for locale in LOCALE_MAP: + name = l10n[locale]["name"] + name_feminine = l10n[locale]["name_feminine"] + name_masculine = l10n[locale]["name_masculine"] + name_neuter = l10n[locale]["name_neuter"] + name_plural = l10n[locale]["name_plural"] + data[locale] = { + f"cook.{cook_effect["name"]}.name": name, + f"cook.{cook_effect["name"]}.name_feminine": name_feminine, + f"cook.{cook_effect["name"]}.name_masculine": name_masculine, + f"cook.{cook_effect["name"]}.name_neuter": name_neuter, + f"cook.{cook_effect["name"]}.name_plural": name_plural, + } + for i, d in enumerate(l10n[locale]["desc"]): + data[locale][f"cook.{cook_effect["name"]}.desc_{i+1}"] = d + for i, d in enumerate(l10n[locale]["elixir_desc"]): + data[locale][f"cook.{cook_effect["name"]}.elixir_desc_{i+1}"] = d + + return data + +def load_entries_for_special_status(special_status_file) -> dict[str, dict[str, str]] | None: + """Load l10n entries from SpecialStatus/*.yaml""" + + with open(special_status_file, "r", encoding="utf-8") as f: + special_status = yaml.safe_load(f) + l10n = special_status["localization"] + if not l10n: + return None + data = {} + name = special_status["name"] + for locale in LOCALE_MAP: + value = l10n[locale] + # Some modifiers doesn't show the value in game + # we add it + if name in ["RapidFire", "LongThrow", "SpreadFire", "SurfMaster"]: + value += " [{{modifier_value}}]" + if name == "SurfMaster" and (locale == "zh-CN" or locale == "zh-TW"): + value = "\u76fe\u6ed1\u884c\u63d0\u5347 [{{modifier_value}}]" + + data[locale] = { + f"status.{name}": value, + } + + # patch for missing entries for Shield Surf Up + return data + +if __name__ == "__main__": + main() + diff --git a/packages/research-data/bin/generate-param.py b/packages/research-data/bin/generate-param.py new file mode 100644 index 0000000..40ee116 --- /dev/null +++ b/packages/research-data/bin/generate-param.py @@ -0,0 +1,146 @@ +import yaml +import os +import multiprocessing +import json + +def main(): + home = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + actor_dir = os.path.join(home, "data", "Actor") + actor_files = [os.path.join(actor_dir, f) for f in os.listdir(actor_dir) ] + + print("processing actor files...") + actor_data = {} + with multiprocessing.Pool() as pool: + for result in pool.imap_unordered(process_actor, actor_files): + if result: + actor, data = result + actor_data[actor] = data + print(f"collected data from {len(actor_data)} actors") + + output_path = os.path.join(os.path.dirname(home), "item-system", "src", "data", "ActorData.gen.ts") + content = """ +/** + * This file is generated by generate-param.py + * DO NOT EDIT MANUALLY + */ +import type { ActorData } from "./ActorData.ts"; + +export const ActorDataMap: Record> = JSON.parse(`""" + with open(output_path, "w", encoding="utf-8", newline="\n") as f: + f.write(content) + json_data = json.dumps(actor_data, sort_keys=True, separators=(',', ':')) + f.write(json_data) + f.write("`);\n") + +def process_actor(actor_file) -> tuple[str, dict] | None: + with open(actor_file, "r", encoding="utf-8") as f: + actor = yaml.safe_load(f) + + if not actor["profile"]: + return None + + profile = actor["profile"] + + data = {} + + for tag in actor["tags"]: + if tag == "CanStack": + data["canStack"] = True + if tag == "CannotSell": + data["cannotSell"] = True + + gparam = actor["gparamlist"] + if gparam: + if "armorEffectEffectType" in gparam: + effect_type = gparam["armorEffectEffectType"] + data["armorEffectEffectType"] = effect_type + # See item-system/src/data/enums.ts + EFFECT_MAP = { + "AttackUp": 8, + "ClimbSpeed": 9, + "ClimbSpeedAndBeamPowerUp": 9, + "ResistAncient": 19, + "ResistElectric": 21, + "ResistCold": 20, + "ResistColdAndResistAncient": 20, + "Quietness": 17, + "SwimSpeed": 29, + "SwimSpeedAndResistAncient": 29, + "SnowMove": 26, + "ResistBurn": 13, + "ResistBurnAndResistAncient": 13, + "ResistElectricAndResistAncient": 21, + "ResistHot": 23, + "ResistHotAndWakeWind": 23, + "SandMove": 25, + "ResistLightning": 24, + "ResistFreeze": 22, + } + if effect_type not in EFFECT_MAP: + raise ValueError(f"Armor effect type not mapped: {effect_type}") + data["specialStatus"] = EFFECT_MAP[effect_type] + if "bowIsLeadShot" in gparam: + data["specialStatus"] = 27 + if "bowIsRapidFire" in gparam and gparam["bowIsRapidFire"]: + if "bowRapidFireNum" in gparam and gparam["bowRapidFireNum"] > 0: + data["bowRapidFireNum"] = gparam["bowRapidFireNum"] + if "bowLeadShotNum" in gparam and gparam["bowLeadShotNum"] > 0: + data["bowLeadShotNum"] = gparam["bowLeadShotNum"] + if "bowLeadShotAng" in gparam: + data["bowLeadShotAng"] = gparam["bowLeadShotAng"] + if "bowLeadShotInterval" in gparam: + data["bowLeadShotInterval"] = gparam["bowLeadShotInterval"] + if "bowArrowFirstSpeed" in gparam: + data["bowArrowFirstSpeed"] = gparam["bowArrowFirstSpeed"] + if "bowArrowStabilitySpeed" in gparam: + data["bowArrowStabilitySpeed"] = gparam["bowArrowStabilitySpeed"] + if "bowArrowGravity" in gparam: + data["bowArrowGravity"] = gparam["bowArrowGravity"] + if "bowIsLongRange" in gparam and gparam["bowIsLongRange"]: + data["bowIsLongRange"] = gparam["bowIsLongRange"] + if "bowArrowChargeRate" in gparam: + data["bowArrowChargeRate"] = gparam["bowArrowChargeRate"] + if "bowArrowReloadRate" in gparam: + data["bowArrowReloadRate"] = gparam["bowArrowReloadRate"] + if "bowIsGuardPierce" in gparam and gparam["bowIsGuardPierce"]: + data["bowIsGuardPierce"] = gparam["bowIsGuardPierce"] + if "attackPower" in gparam: + data["attackPower"] = gparam["attackPower"] + if "attackRange" in gparam: + data["attackRange"] = gparam["attackRange"] + if "generalLife" in gparam: + data["generalLife"] = gparam["generalLife"] + if "genrealIsLifeInfinite" in gparam: + data["genrealIsLifeInfinite"] = gparam["genrealIsLifeInfinite"] + if "itemSellingPrice" in gparam: + data["itemSellingPrice"] = gparam["itemSellingPrice"] + if "itemBuyingPrice" in gparam: + data["itemBuyingPrice"] = gparam["itemBuyingPrice"] + if "itemCreatingPrice" in gparam: + data["itemCreatingPrice"] = gparam["itemCreatingPrice"] + if "itemStainColor" in gparam: + data["itemStainColor"] = gparam["itemStainColor"] + if "weaponCommonGuardPower" in gparam: + data["weaponCommonGuardPower"] = gparam["weaponCommonGuardPower"] + if "armorStarNum" in gparam: + data["armorStarNum"] = gparam["armorStarNum"] + if "armorDefenceAddLevel" in gparam: + data["armorDefenceAddLevel"] = gparam["armorDefenceAddLevel"] + + if not data: + return None + + # filter out if it only has generalLife (some animals) + if len(data) == 1 and "generalLife" in data: + return None + + # filter out if it only has attackPower and life (some animals) + if len(data) == 2 and "attackPower" in data and "generalLife" in data: + return None + + data["profile"] = profile + + return actor["actor"], data + +if __name__ == "__main__": + main() diff --git a/packages/research-data/bin/generate.py b/packages/research-data/bin/generate.py new file mode 100644 index 0000000..d9c1cfd --- /dev/null +++ b/packages/research-data/bin/generate.py @@ -0,0 +1,838 @@ +import os +import shutil +import subprocess +import yaml +import json +from dataclasses import dataclass + +DEBUG_PRINT = False + +def extend_yaml(): + def dict_ctor(loader, node): + values = loader.construct_mapping(node) + return dict(values) + + def str_ctor(loader, node): + values = loader.construct_scalar(node) + return str(values) + + def int_ctor(loader, node): + values = loader.construct_scalar(node) + return int(values, 0) + + def list_ctor(loader, node): + values = loader.construct_sequence(node) + return list(values) + + yaml.add_constructor('!list', dict_ctor) + yaml.add_constructor('!obj', dict_ctor) + yaml.add_constructor('!io', dict_ctor) + yaml.add_constructor('!str64', str_ctor) + yaml.add_constructor('!str32', str_ctor) + yaml.add_constructor('!str256', str_ctor) + yaml.add_constructor('!vec3', list_ctor) + yaml.add_constructor('!u', int_ctor) + +def assertion(value, message = "Assertion failed"): + if not value: + raise AssertionError(message) + + +SCRIPT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +DATA_DIR = os.path.join(SCRIPT_DIR, "data") +BOTW_DATA_PATH = os.path.join(DATA_DIR, "botw") +BOTW_DATA_REPO = "https://github.com/leoetlino/botw" +BOTW_DATA_BRANCH = "master" +BOTW_DATA_CHECKOUT = [ + "Actor/ActorLink", + "Actor/GeneralParamList", + "Message", +] + +def download_data_if_needed(): + def check_paths(): + for path in BOTW_DATA_CHECKOUT: + path = os.path.join(BOTW_DATA_PATH, path) + if not os.path.exists(path): + return False + return True + def sparse_checkout(repo, path, branch, checkout_paths): + git = shutil.which("git") + if not git: + raise Exception("git not found") + subprocess.run([git, "init"], cwd=path) + subprocess.run([git, "remote", "add", "origin", repo], cwd=path) + subprocess.run([git, "config", "core.sparseCheckout", "true"], cwd=path) + with open(os.path.join(path, ".git", "info", "sparse-checkout"), "w", encoding="utf-8") as f: + for checkout_path in checkout_paths: + f.write(checkout_path + "\n") + subprocess.run([git, "pull", "--depth=1", "origin", branch], cwd=path) + if not check_paths(): + print("missing data files, cloning repositories...") + try: + if os.path.exists(DATA_DIR): + shutil.rmtree(DATA_DIR) + os.makedirs(BOTW_DATA_PATH) + sparse_checkout(BOTW_DATA_REPO, BOTW_DATA_PATH, BOTW_DATA_BRANCH, BOTW_DATA_CHECKOUT) + if not check_paths(): + print("still missing files after cloning. Exiting.") + exit(1) + else: + print("data files cloned successfully.") + except Exception as e: + print(e) + print() + print("fail to get data files. Please clone them manually or try again.") + exit(1) + else: + print("found data files, skipping cloning.") + +def emit_actor_data(actors, gparamlists, localization): + actor_dir = os.path.join(DATA_DIR, "Actor") + if os.path.exists(actor_dir): + shutil.rmtree(actor_dir) + os.makedirs(actor_dir) + + print("writing actor files...") + + for actor_name, actor in actors.items(): + if DEBUG_PRINT: + print(f"-- {actor_name}") + with open(os.path.join(actor_dir, f"{actor_name}.yaml"), "w", encoding="utf-8", newline="\n") as f: + f.write(f"actor: {actor_name}\n") + f.write(f"name_jpn: {actor.name_jpn}\n") + if actor.tags: + f.write("tags:\n") + for tag in actor.tags: + f.write(f" - {tag}\n") + else: + f.write("tags: []\n") + if actor.model: + f.write(f"model: {actor.model}\n") + else: + f.write("model: null\n") + if actor.gparamlist: + f.write(f"gparamlist:\n") + f.write(f" user: {actor.gparamlist}\n") + f.write(f" # ---\n") + for key, value in gparamlists[actor.gparamlist]: + if isinstance(value, list): + data = json.dumps(value) + f.write(f" {key}: {data}\n") + else: + data = yaml.dump({key: value}) + f.write(f" {data}") + if not data.endswith("\n"): + f.write("\n") + else: + f.write("gparamlist: null\n") + if actor.profile: + f.write(f"profile: {actor.profile}\n") + else: + f.write("profile: null\n") + if actor_name in localization: + l = localization[actor_name] + assertion(l.profile == actor.profile, f"Profile mismatch for {actor_name}") + f.write("localization:\n") + for locale in LOCALE_MAP: + f.write(f" {locale}:\n") + strings = l.strings[locale] + name = json.dumps(strings.name) + name_attr = json.dumps(strings.name_attr) + f.write(f" name:\n") + f.write(f" text: {name}\n") + f.write(f" attr: {name_attr}\n") + desc = json.dumps(strings.desc) + f.write(f" desc: {desc}\n") + album_desc = json.dumps(strings.album_desc) + f.write(f" album_desc: {album_desc}\n") + else: + f.write("localization: null\n") + + +class ActorLink: + actor: str + name_jpn: str + tags: list[str] + model: str = "" + gparamlist: str = "" + profile: str = "" + +def load_actor_links() -> dict[str, ActorLink]: + print("loading actor links...") + actor_links = {} + actor_link_path = os.path.join(BOTW_DATA_PATH, "Actor", "ActorLink") + for file in os.listdir(actor_link_path): + if DEBUG_PRINT: + print(f"-- {file}") + assertion(file.endswith(".yml"), "ActorLink file must end in .yml") + actor_name = file[:-4] + with open(os.path.join(actor_link_path, file), "r", encoding="utf-8") as f: + actor = ActorLink() + actor.actor = actor_name.strip() + actor.tags = [] + + data = yaml.load(f, yaml.FullLoader) + assertion(data, "ActorLink data must not be empty") + assertion("param_root" in data, "ActorLink data must have 'param_root'") + param_root = data["param_root"] + assertion(param_root, "ActorLink data must have valid 'param_root'") + assertion("objects" in param_root, "ActorLink param_root must have 'objects'") + objects = param_root["objects"] + assertion(objects, "ActorLink param_root must have valid 'objects'") + assertion("LinkTarget" in objects, "ActorLink objects must have 'LinkTarget'") + link_targets = objects["LinkTarget"] + assertion(link_targets, "ActorLink objects must have valid 'LinkTarget'") + assertion("ActorNameJpn" in link_targets, "ActorLink LinkTargets must have 'ActorNameJpn'") + + name_jpn = link_targets["ActorNameJpn"] + assertion(name_jpn and isinstance(name_jpn, str), "ActorLink LinkTargets ActorNameJpn must be a string") + actor.name_jpn = name_jpn + + if "ModelUser" in link_targets: + model = link_targets["ModelUser"] + assertion(model and isinstance(model, str), "ActorLink LinkTargets ModelUser must be a string") + if model == "Dummy": + model = "" + actor.model = model.strip() + + if "GParamUser" in link_targets: + gparamlist = link_targets["GParamUser"] + assertion(gparamlist and isinstance(gparamlist, str), "ActorLink LinkTargets GParamUser must be a string") + if gparamlist == "Dummy": + gparamlist = "" + actor.gparamlist = gparamlist.strip() + + if "ProfileUser" in link_targets: + profile = link_targets["ProfileUser"] + assertion(profile and isinstance(profile, str), "ActorLink LinkTargets ProfileUser must be a string") + if profile == "Dummy": + profile = "" + actor.profile = profile.strip() + + if "Tags" in objects: + tags = objects["Tags"] + # print(tags) + assertion(tags and isinstance(tags, dict), "ActorLink objects Tags must be a dict") + for i in range(0, 99): # at most 20 something tags + tag_name = f"Tag{i}" + if tag_name not in tags: + break + tag = tags[tag_name] + assertion(tag and isinstance(tag, str), f"ActorLink objects Tags {tag_name} must be a string") + actor.tags.append(tag.strip()) + + assertion(len(actor.tags) == len(set(actor.tags)), + f"{actor_name}: ActorLink tags must be unique, but got: {actor.tags}, {len(actor.tags)}, {len(set(actor.tags))}") + actor_links[actor_name] = actor + + + print(f"loaded {len(actor_links)} actors") + return actor_links + +@dataclass +class GparamKey: + name: str + default: str | int | float | bool | None +def load_gparam_keys() -> list[GparamKey]: + print("loading gparamkeys...") + gparam_path = os.path.join(BOTW_DATA_PATH, "Actor", "GeneralParamList", "Dummy.gparamlist.yml") + keys = [] + with open(gparam_path, "r", encoding="utf-8") as f: + # not using YAML parser for the whole thing to preserve key order + current_key_prefix: str = "" + current_table: list[str] = [] + for line in f: + if not line.startswith(" "): + continue + line = line[4:] + if not line.startswith(" "): + if current_table: + # table end + data = yaml.load("\n".join(current_table), yaml.FullLoader) + assertion(data and isinstance(data, dict) and len(data) == 1, "Table must not be empty") + current_key= list(data.keys())[0] + current_key_prefix = current_key[0].lower() + current_key[1:] + data = data[current_key] + for key in sorted(data.keys()): + keys.append(GparamKey(current_key_prefix + key, data[key])) + + current_table = [] + current_key_prefix = "" + + line = line.strip() + if line.endswith("!obj") or line.endswith(":"): + # line is just table name + key = line.split(":")[0].strip() + current_key_prefix = key[0].lower() + key[1:] + else: + # table inline (need to parse whole table together) + current_table = [line] + continue + if current_table: + current_table.append(line) + continue + line = line.strip() + data = yaml.load(line, yaml.FullLoader) + assertion(data and isinstance(data, dict) and len(data) == 1, "Data must not be empty") + key = list(data.keys())[0] + keys.append(GparamKey(current_key_prefix+key, data[key])) + print(f"loaded {len(keys)} gparamkeys") + if DEBUG_PRINT: + for key in keys: + data = yaml.dump({key.name: key.default}) + print(data) + + return keys + +def parse_gpl(obj): + out = {} + for key in obj: + lower = key[0].lower() + key[1:] + for subkey in obj[key]: + out[lower + subkey] = obj[key][subkey] + return out + +def load_gparamlist(keys: list[GparamKey]) -> dict[str, list[tuple[str, object]]]: + print("loading gparamlists...") + gparamlist = {} + gparam_path = os.path.join(BOTW_DATA_PATH, "Actor", "GeneralParamList") + + for file in os.listdir(gparam_path): + if DEBUG_PRINT: + print(f"-- {file}") + assertion(file.endswith(".gparamlist.yml"), "GParamList file must end in .yml") + gparam_name = file[:-15] + with open(os.path.join(gparam_path, file), "r", encoding="utf-8") as f: + data = yaml.load(f, yaml.FullLoader) + assertion(data, "GParamList data must not be empty") + assertion("param_root" in data, "GParamList data must have 'param_root'") + param_root = data["param_root"] + assertion(param_root, "GParamList data must have valid 'param_root'") + assertion("objects" in param_root, "GParamList param_root must have 'objects'") + objects = parse_gpl(param_root["objects"]) + + parsed = [] + + for key in keys: + name = key.name + if name not in objects: + continue + value = objects[name] + del objects[name] + if value == key.default: + continue + if value is None: + raise ValueError(f"Key {name} in {gparam_name} is None") + parsed.append((name, value)) + + unknown_keys = set(objects.keys()) + if unknown_keys: + print(objects) + raise ValueError(f"Unknown keys in {gparam_name}: {unknown_keys}") + + gparamlist[gparam_name] = parsed + + print(f"loaded {len(gparamlist)} gparamlists") + + return gparamlist + +@dataclass +class LocalizationStrings: + name: str = "" + name_attr: str = "" + desc: str = "" + album_desc: str = "" + +@dataclass +class LocalizationEntry: + profile: str + strings: dict[str, LocalizationStrings] + +LOCALE_MAP = { + "en-US": "USen", + "ja-JP": "JPja", + "de-DE": "EUde", + "es-ES": "EUes", + "it-IT": "EUit", + "fr-FR": "EUfr", + "ru-RU": "EUru", + "zh-CN": "CNzh", + "zh-TW": "TWzh", + "ko-KR": "KRko", + "nl-NL": "EUnl", +} +def load_actor_localization() -> dict[str, LocalizationEntry]: + print("loading localization...") + entries = {} + for locale, locale_nin in LOCALE_MAP.items(): + load_l10n_for_locale(locale, locale_nin, entries) + print(f"loaded {len(entries)} entries") + return entries + +def load_l10n_for_locale(locale: str, locale_nin: str, entries: dict[str, LocalizationEntry]): + localization_path = os.path.join(BOTW_DATA_PATH, "Message", f"Msg_{locale_nin}.product.sarc", "ActorType") + + for file in os.listdir(localization_path): + assertion(file.endswith(".msyt"), "Localization file must end in .msyt") + profile = file[:-5] + with open(os.path.join(localization_path, file), "r", encoding="utf-8") as f: + data = yaml.load(f, yaml.FullLoader) + load_l10n_for_locale_profile(locale, profile, data, entries) + +def load_l10n_for_locale_profile(locale: str, profile: str, data, entries: dict[str, LocalizationEntry]): + assertion(data and isinstance(data, dict) and "entries" in data, "Localization data must have 'entries'") + entries_data = data["entries"] + assertion(isinstance(entries_data, dict), "Localization entries must be a dict") + for entry_name, entry_data in entries_data.items(): + if entry_name.endswith("_Name"): + actor_name = entry_name[:-5] + text, attr = parse_localization(entry_name, entry_data, True ) + strings = ensure_l10n_entry(entries, profile, actor_name, locale) + strings.name = text + strings.name_attr = attr + elif entry_name.endswith("_Desc"): + actor_name = entry_name[:-5] + text, attr = parse_localization(entry_name, entry_data, False ) + strings = ensure_l10n_entry(entries, profile, actor_name, locale) + strings.desc = text + elif entry_name.endswith("_PictureBook"): + actor_name = entry_name[:-13] + text, attr = parse_localization(entry_name, entry_data, False ) + strings = ensure_l10n_entry(entries, profile, actor_name, locale) + strings.album_desc = text + +def parse_localization(name, data, allow_attr): + assertion(isinstance(data, dict) and "contents" in data and len(data) == 1, "Localization data must have 'contents'") + contents = data["contents"] + text = "" + attr = "" + last_control = None + + for x in contents: + if "text" in x: + if last_control: + text += x["text"][last_control:] + last_control = None + else: + text += x["text"] + continue + assertion("control" in x and len(x) == 1, f"{name}: Entry must have either text or control") + c = x["control"] + assertion("kind" in c and isinstance(c["kind"], str), f"{name}: Control must have kind") + kind = c["kind"] + if kind == "raw": + if "zero" in c: + # katakana marking above kanji + try: + last_control = c["zero"]["zero"]["field_3"] + except KeyError: + raise ValueError(f"failed to parse control for {name}") + + # divided by 2 because it's in bytes + assertion(last_control % 2 == 0, "Odd number of bytes to remove") + last_control = last_control // 2 + continue + + if "two" in c: + # effect and effect description placeholder + one_field_value = c["two"]["one_field"][0] + if one_field_value == 7: + text += "{{effect}}" + elif one_field_value == 8: + text += "{{effect_desc}}" + elif one_field_value == 13: + text += "{{modifier_value}}" + else: + raise ValueError(f"{name} invalid two.one_field0: {one_field_value}") + continue + + if "two_hundred_one" in c: + # See exefs/main/sub_7100AA4B4C + if allow_attr: + assertion("dynamic" in c["two_hundred_one"], "two_hundred_one must have dynamic") + dynamic = c["two_hundred_one"]["dynamic"] + assertion("field_2" in dynamic[1]) + v = dynamic[1]["field_2"] + assertion(len(v) == 4, "dynamic field_2 must have 4 elements") + plural = v[3] + assertion(plural == 0 or plural == 1, "plural must be 0 or 1") + plural = plural == 1 + if v[0] == 0: + t = "" + elif v[0] == 1: + t = "masculine" + elif v[0] == 2: + t = "feminine" + elif v[0] == 3: + t = "neuter" + else: + raise ValueError(f"{name} invalid dynamic field_2: {v}") + if plural: + attr = "plural" + else: + attr = t + continue + + raise ValueError(f"{name} invalid raw control: {c}") + + return text, attr + +def ensure_l10n_entry(entries: dict[str, LocalizationEntry], profile: str, actor: str, locale: str) -> LocalizationStrings: + if actor not in entries: + strings = {} + for l in LOCALE_MAP: + strings[l] = LocalizationStrings() + entries[actor] = LocalizationEntry(profile, strings) + entry = entries[actor] + return entry.strings[locale] + +# unused +def filter_actor(name): + """Return True if the actor is an item (should be processed)""" + # Weapons + if name.startswith("Weapon_Sword_"): + if name.endswith("_071"): # Cutscene MS + return False + if name.endswith("_072"): # True MS for icon (?) + return False + if name.endswith("_080"): # TOTS Cutscene MS + return False + if name.endswith("_081"): # TOTS Cutscene True MS + return False + if name.endswith("_500"): # ? + return False + if name.endswith("_501"): # Korok Stick Cutscene + return False + if name.endswith("_503"): # Cutscene OHO + return True + return True + if name.startswith("Weapon_Lsword_"): + return True + if name.startswith("Weapon_Spear_"): + if name.endswith("_080"): # Lightscale Cutscene + return False + return True + if name.startswith("Weapon_Bow_"): + if name.endswith("_080"): # GEB Cutscene + return False + return True + if name in ("NormalArrow", "FireArrow", "IceArrow", "ElectricArrow", "BombArrow_A", "AncientArrow"): + return True + if name.startswith("Weapon_Shield_"): + return True + if name.startswith("Armor_"): + if name.startswith("Armor_Default"): + return False + if name.endswith("_B"): # ? + return False + return True + if name in ( + "Item_Fruit_D", + "Item_Fruit_G", + "Item_Fruit_A", + "Item_Fruit_B", + "Item_Fruit_F", + "Item_Fruit_I", + "Item_Fruit_C", + "Item_Fruit_E", + "Item_Fruit_H", + "Item_Mushroom_N", + "Item_Mushroom_F", + "Item_Mushroom_O", + "Item_Mushroom_E", + "Item_Mushroom_A", + "Item_Mushroom_B", + "Item_Mushroom_C", + "Item_Mushroom_H", + "Item_Mushroom_D", + "Item_Mushroom_L", + "Item_Mushroom_M", + "Item_Mushroom_J", + ): + return True + if name.startswith("Item_Enemy_"): + if name == "Item_Enemy_Put_57": # placed octo balloon (?) + return False + return True + if name.startswith("Item_FishGet_"): + if name.endswith("L_00"): # multiple fish + return False + return True + if name.startswith("Item_Fruit_"): + if name.endswith("E_00"): # multiple lotus + return False + return True + if name.startswith("Item_InsectGet_"): + return True + if name.startswith("Item_Material_"): + if name.endswith("05_00"): # multiple milk + return False + return True + if name.startswith("Item_Meat_"): + return True + if name.startswith("Item_Mushroom_"): + if name.endswith("_00"): # multiple + return False + return True + if name.startswith("Item_Ore_"): + if name.endswith("A_00"): # multiple diamond + return False + return True + return False + +def emit_effects(): + def static_msg_file(locale_nin, file): + return os.path.join(BOTW_DATA_PATH, "Message", f"Msg_{locale_nin}.product.sarc", "StaticMsg", file) + # This is the effect displayed on the player/weapon + # Could come from: + # - Weapon modifier + # - Meal effect + # - Armor effect + # Ordered by appearance in SpecialStatus.myst + SPECIAL_STATUS_TABLE = [ + "AddGuardPlus", # (wpmod) Yellow Shield Guard Up + "AddGuard", # (wpmod) Blue Shield Guard Up + "AddLifePlus", # (wpmod) Yellow Durability Up + "AddLife", # (wpmod) Blue Durability Up + "AddPowerPlus", # (wpmod) Yellow Attack Up + "AddPower", # (wpmod) Blue Attack Up + "AllSpeed", # (meal) Movement Speed Up + "AttackUp", # (meal/armor) Attack Up + # -- The CompletionBonus (armor set bonus) are skipped + "ClimbSpeedUp", # (armor) Climbing Speed Up + "Critical", # (wpmod) Critical Hit + "DefenseUp", # (meal) Defense Up + "ExGutsMaxUp", # (meal) Endura + "Fireproof", # (meal) Fireproof // I think set bonus is also this? + "GutsRecover", # (meal) Stamina recover + "LifeMaxUp", # (meal) Hearty/yellow hearts + "LongThrow", # (wpmod) Long Throw + "Quietness", # (meal/armor) Stealth Up + "RapidFire", # (wpmod) Quick Shot + "ReduceAncientEnemyDamge", # (armor) ancient/ diamond circlet/midna, didn't spell wrong + "ResistCold", # (meal/armor) Cold Resistance + "ResistElectric", # (meal/armor) Shock Resistance + "ResistFreeze", # (armor) unfreezable + "ResistHot", # (meal/armor) Heat Resistance + "ResistLightning", # (armor) Lightning Proof + "SandMoveSpeedUp", # (armor) Sand Speed Up + "SnowMovingSpeed", # (armor) Snow Speed Up + "SpreadFire", # (wpmod) Multi-Shot + "SurfMaster", # (wpmod) Shield surf friction minus + "SwimSpeedUp", # (armor) Swim Speed Up + ] + # [ + # hash name in CookData.System, + # effect name in translation, <- used as name + # effect name in code, + # CookEffectId value, + # SpecialStatus name + # ] + # For CookData.System, see: + # - https://github.com/Pistonite/botw-recipe/blob/main/research/output/cookdata-system.yaml + # which is decoded from Cooking/CookData.yaml from leoetlino/botw + # For code values, see cookManager.cpp and cookManager.h in botw decomp + # Ordered by CookData.System + # + # Note that LifeRecover has no translation entry + COOK_EFFECTS = [ + ["StaminaRecover", "GutsRecover", "GutsRecover", 14, "GutsRecover"], + ["GutsPerformance", "ExGutsMaxUp", "ExGutsMaxUp", 15, "ExGutsMaxUp"], + ["LifeRecover", "LifeRecover", "LifeRecover", 1 , None], + ["LifeMaxUp", "LifeMaxUp", "LifeMaxUp", 2 , "LifeMaxUp"], + ["ResistHot", "ResistHot", "ResistHot", 4 , "ResistHot"], + ["ResistCold", "ResistCold", "ResistCold", 5 , "ResistCold"], + ["ResistElectric", "ResistElectric", "ResistElectric", 6 , "ResistElectric"], + ["AllSpeed", "AllSpeed", "MovingSpeed", 13, "AllSpeed"], + ["AttackUp", "AttackUp", "AttackUp", 10, "AttackUp"], + ["DefenseUp", "DefenseUp", "DefenseUp", 11, "DefenseUp"], + ["Quietness", "Quietness", "Quietness", 12, "Quietness"], + ["Fireproof", "Fireproof", "Fireproof", 16, "Fireproof"], + ] + def lookup_linked_cook_effect(special_status): + for _, cook_effect, _, _, ss in COOK_EFFECTS: + if ss == special_status: + return cook_effect + return None + + + # [ + # internal name, <- used as name + # botw decomp name (WeaponModifier), + # code value, + # SpecialStatus name + # Yellow Special Status name + # ] + WEAPON_MODIFIERS = [ + ["None", "None", 0, None, None], + ["AddPower", "AddAtk", 0x1, "AddPower", "AddPowerPlus"], + ["AddLife", "AddLife", 0x2, "AddLife", "AddLifePlus"], + ["Critical", "AddCrit", 0x4, "Critical", "Critical"], + ["LongThrow", "AddThrow", 0x8, "LongThrow", "LongThrow"], + ["SpreadFire", "AddSpreadFire", 0x10, "SpreadFire", "SpreadFire"], + ["Zoom", "AddZoomRapid", 0x20, None, None], + ["RapidFire", "AddRapidFire", 0x40, "RapidFire", "RapidFire"], + ["SurfMaster", "AddSurfMaster", 0x80, "SurfMaster", "SurfMaster"], + ["AddGuard", "AddGuard", 0x100, "AddGuard", "AddGuardPlus"], + ] + def lookup_linked_weapon_modifier(special_status): + for wm_name, _, _, ss, ss_yellow in WEAPON_MODIFIERS: + if ss == special_status or ss_yellow == special_status: + return wm_name + return None + print("loading special status effects...") + special_status_localization = {} + for locale, locale_nin in LOCALE_MAP.items(): + with open(static_msg_file(locale_nin, "SpecialStatus.msyt"), "r", encoding="utf-8") as f: + entries_data = yaml.load(f, yaml.FullLoader)["entries"] + for name, data in entries_data.items(): + assertion(name.endswith("_Name"), f"SpecialStatus entry must end in _Name: {name}") + special_status_name = name[:-5] + if special_status_name not in special_status_localization: + special_status_localization[special_status_name] = {} + text, _= parse_localization(name, data, False) + special_status_localization[special_status_name][locale] = text + print("writing special status files...") + SPECIAL_STATUS_DIR = os.path.join(DATA_DIR, "SpecialStatus") + if os.path.exists(SPECIAL_STATUS_DIR): + shutil.rmtree(SPECIAL_STATUS_DIR) + os.makedirs(SPECIAL_STATUS_DIR) + for special_status in SPECIAL_STATUS_TABLE: + with open(os.path.join(SPECIAL_STATUS_DIR, f"{special_status}.yaml"), "w", encoding="utf-8", newline="\n") as f: + f.write(f"name: {special_status}\n") + cook_effect = lookup_linked_cook_effect(special_status) + if cook_effect: + f.write(f"cook_effect: {cook_effect}\n") + else: + f.write("cook_effect: null\n") + weapon_modifier = lookup_linked_weapon_modifier(special_status) + if weapon_modifier: + f.write(f"weapon_modifier: {weapon_modifier}\n") + else: + f.write("weapon_modifier: null\n") + f.write("localization:\n") + for locale in LOCALE_MAP: + text = special_status_localization[special_status][locale] + f.write(f" {locale}: {json.dumps(text)}\n") + # Special file for zoom + ZOOM_STATUS = """ +name: Zoom +cook_effect: null +weapon_modifier: Zoom +localization: + en-US: "Zoom" + ja-JP: "\\u30ba\\u30fc\\u30e0" + de-DE: "Zoom" + es-ES: "Zoom" + it-IT: "Zoom" + fr-FR: "Zoom" + ru-RU: "\\u0431\\u0435\\u043a\\u0430\\u0441" + zh-CN: "\\u500d\\u955c" + zh-TW: "\\u500d\\u93e1" + ko-KR: "\\ub3cb\\ubcf4\\uae30" + nl-NL: "Zoom" +""" + with open(os.path.join(SPECIAL_STATUS_DIR, "Zoom.yaml"), "w", encoding="utf-8", newline="\n") as f: + f.write(ZOOM_STATUS) + + print("loading cook effects...") + cook_effect_localization = {} + for locale, locale_nin in LOCALE_MAP.items(): + with open(static_msg_file(locale_nin, "CookEffect.msyt"), "r", encoding="utf-8") as f: + entries_data = yaml.load(f, yaml.FullLoader)["entries"] + for name, data in entries_data.items(): + parts = name.split("_", 1) + effect_name = parts[0] + rest = parts[1] if len(parts) > 1 else "" + if effect_name not in cook_effect_localization: + cook_effect_localization[effect_name] = {} + for l in LOCALE_MAP: + cook_effect_localization[effect_name][l] = {} + if rest == "Name": + text, _ = parse_localization(name, data, False) + cook_effect_localization[effect_name][locale]["name"] = text + elif rest == "Name_Feminine": + text, _ = parse_localization(name, data, False) + cook_effect_localization[effect_name][locale]["name_feminine"] = text + elif rest == "Name_Masculine": + text, _ = parse_localization(name, data, False) + cook_effect_localization[effect_name][locale]["name_masculine"] = text + elif rest == "Name_Neuter": + text, _ = parse_localization(name, data, False) + cook_effect_localization[effect_name][locale]["name_neuter"] = text + elif rest == "Name_Plural": + text, _ = parse_localization(name, data, False) + cook_effect_localization[effect_name][locale]["name_plural"] = text + elif rest.startswith("Desc"): + parts = rest.split("_", 1) + desc_level = (int(parts[1]) - 1) if len(parts) > 1 else 0 + if "desc" not in cook_effect_localization[effect_name][locale]: + cook_effect_localization[effect_name][locale]["desc"] = [] + desc_array = cook_effect_localization[effect_name][locale]["desc"] + if len(desc_array) <= desc_level: + desc_array.extend([""] * (desc_level - len(desc_array) + 1)) + text, _ = parse_localization(name, data, False) + desc_array[desc_level] = text + elif rest.startswith("MedicineDesc"): + parts = rest.split("_", 1) + desc_level = (int(parts[1]) - 1) if len(parts) > 1 else 0 + if "elixir_desc" not in cook_effect_localization[effect_name][locale]: + cook_effect_localization[effect_name][locale]["elixir_desc"] = [] + desc_array = cook_effect_localization[effect_name][locale]["elixir_desc"] + if len(desc_array) <= desc_level: + desc_array.extend([""] * (desc_level - len(desc_array) + 1)) + text, _ = parse_localization(name, data, False) + desc_array[desc_level] = text + else: + raise ValueError(f"Unknown cook effect entry in {name}") + COOK_EFFECT_DIR = os.path.join(DATA_DIR, "CookEffect") + if os.path.exists(COOK_EFFECT_DIR): + shutil.rmtree(COOK_EFFECT_DIR) + os.makedirs(COOK_EFFECT_DIR) + for system_name, name, code_name, value, special_status in COOK_EFFECTS: + with open(os.path.join(COOK_EFFECT_DIR, name + ".yaml"), "w", encoding="utf-8", newline="\n") as f: + f.write(f"name: {name}\n") + f.write(f"system_name: {system_name}\n") + f.write(f"code_name: {code_name}\n") + f.write(f"value: {value}\n") + if special_status: + f.write(f"special_status: {special_status}\n") + else: + f.write("special_status: null\n") + if name in cook_effect_localization: + f.write("localization:\n") + l10n_data = cook_effect_localization[name] + for locale, data in l10n_data.items(): + f.write(f" {locale}:\n") + f.write(f" name: {json.dumps(data['name'])}\n") + f.write(f" name_feminine: {json.dumps(data['name_feminine'])}\n") + f.write(f" name_masculine: {json.dumps(data['name_masculine'])}\n") + f.write(f" name_neuter: {json.dumps(data['name_neuter'])}\n") + f.write(f" name_plural: {json.dumps(data['name_plural'])}\n") + f.write(f" desc:\n") + for desc in data["desc"]: + f.write(f" - {json.dumps(desc)}\n") + f.write(f" elixir_desc:\n") + for desc in data["elixir_desc"]: + f.write(f" - {json.dumps(desc)}\n") + else: + f.write("localization: null\n") + + + + + + + +if __name__ == "__main__": + extend_yaml() + download_data_if_needed() + gparamkeys = load_gparam_keys() + actors = load_actor_links() + gparamlists = load_gparamlist(gparamkeys) + localization = load_actor_localization() + + emit_actor_data(actors, gparamlists, localization) + emit_effects() + diff --git a/packages/research-data/bin/resolve-icon-actor.py b/packages/research-data/bin/resolve-icon-actor.py new file mode 100644 index 0000000..a8d8e9d --- /dev/null +++ b/packages/research-data/bin/resolve-icon-actor.py @@ -0,0 +1,150 @@ +import os +import yaml +import multiprocessing +import json + +ignore_name = set([ + # Not Items (don't have icon anyway) + "Korok", + "Traveler", + "???", + "Remote Bomb", + "Remote Bomb +", + "Monument Shard", + "Finley", + "Great Fairy Fountain", + + # Manually duplicated + "Thunder Helm", + + # Two distinct items with same name + "Light Arrows", +]) + +manual_name = { + "Weapon_Sword_071": "Master Sword", + "Weapon_Sword_072": "Master Sword", +} + +def main(): + home = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + actor_dir = os.path.join(home, "data", "Actor") + actor_files = [ os.path.join(actor_dir, x) for x in os.listdir(actor_dir)] + + name_to_actor_and_icon = {} + + print("processing actors...") + # process each actor + with multiprocessing.Pool() as pool: + for result in pool.imap_unordered(process_actor, actor_files): + if not result: + continue + + name, actor_name, icon_actor_name = result + if name in name_to_actor_and_icon: + data = name_to_actor_and_icon[name] + data["actors"].append(actor_name) + data["icons"].add(icon_actor_name) + else: + data = { + "actors": [actor_name], + "icons": set([icon_actor_name]), + } + name_to_actor_and_icon[name] = data + + print("resolving actor icons...") + + manual_resolution = { + "Snow Boots": "Armor_141_Lower", + "Master Sword": "Weapon_Sword_070", + "Sheikah Slate": "Obj_DRStone_Get", + } + + # actor name -> icon actor name, if not the same + resolution = {} + + for name in name_to_actor_and_icon: + data = name_to_actor_and_icon[name] + actors = data["actors"] + # if only one actor has this name, skip + if len(actors) <= 1: + continue + icons = data["icons"] + if len(icons) > 1: + # more than one icon, needs manual resolution + if name not in manual_resolution: + print(f"actors: {actors}") + print(f"icons: {icons}") + raise Exception(f"Manual resolution needed for {name}") + icon = manual_resolution[name] + if icon not in icons: + raise Exception(f"In manual resolution for {name}: Icon {icon} not in {icons}") + for actor in actors: + if actor != icon: + print(f"{actor} -> {icon}") + resolution[actor] = icon + else: + icon = next(iter(icons)) + # only one icon, resolve to it + for actor in actors: + if actor != icon: + print(f"{actor} -> {icon}") + resolution[actor] = icon + + print("saving resolution output...") + output_path = os.path.join(os.path.dirname(home), "item-sprites", "src", "ActorRemap.gen.ts") + save_typescript(output_path, resolution) + +def process_actor(actor_path) -> tuple[str, str, str] | None: + """ + Return (localized_name, actor_name, icon_actor_name) + Return None if actor doesn't have translation + """ + with open(actor_path, "r", encoding="utf-8") as f: + actor = yaml.safe_load(f) + actor_name = actor["actor"] + + # load the localized name + if actor_name in manual_name: + name = manual_name[actor_name] + else: + if not actor["localization"]: + return None + strings = actor["localization"]["en-US"] + if not strings["name"]: + return None + name = strings["name"]["text"] + if name in ignore_name: + return None + + # find the icon actor from gparam + icon_actor = actor_name + if actor["gparamlist"]: + if "itemUseIconActorName" in actor["gparamlist"]: + icon_actor = actor["gparamlist"]["itemUseIconActorName"] + + return (name, actor_name, icon_actor) + + +def save_typescript(path, resolution): + + content = """ +/** + * This file is generated by resolve-icon-actor.py + * DO NOT EDIT MANUALLY + */ + +/** Actor name -> icon actor name, if different */ +export type ActorRemap = Record; + """ + + with open(path, "w", encoding="utf-8", newline="\n") as f: + f.write(content) + f.write("\n") + f.write("export const ActorRemap: ActorRemap = JSON.parse(`") + json.dump(resolution, f, separators=(',', ':')) # minify + f.write("`);\n") + +if __name__ == "__main__": + main() + diff --git a/packages/research-data/src/Actor.ts b/packages/research-data/src/Actor.ts new file mode 100644 index 0000000..3e6c4fe --- /dev/null +++ b/packages/research-data/src/Actor.ts @@ -0,0 +1,83 @@ +/** + * Schema for Actor/*.yaml files (* is actor name) + */ +import type { Locale } from "./common.ts"; + +/** + * Schema of the Actor/*.yaml file + * + * Note that non-optional fields are always present, but maybe null + * as indicated by the type + */ +export type Actor = { + /** Name of the actor, also the file name */ + actor: string; + /** The ActorNameJpn of the actor */ + name_jpn: string; + /** Tags of the actor, as defined in the ActorLink */ + tags: string[]; + /** The ModelUser of the actor */ + model: string | null; + /** The GeneralParamList of the actor, as defined by GParamUser */ + gparamlist: GParamList | null; + /** The ProfileUser of the actor */ + profile: string | null; + /** The localization strings of the actor */ + localization: Record | null; +} + +/** + * Schema for the GeneralParamList + * + * Each key is formated as they appear in ActorInfo, like + * categorySubKey (camelCase) + */ +export type GParamList = { + /** The GParamUser */ + user: string +} & Record; + +export type GParamValue = string | number | boolean | number[]; + +/** Localization entry for an actor */ +export type ActorL10nEntry = { + /** + * The name of the actor + * + * If the actor is a CookResult, + * the effect is represented as {{effect}} + */ + name: ActorL10nString; + /** + * The description of the actor + * + * If the actor is a CookResult, + * the effect is represented as {{effect_desc}} + */ + desc: string; + /** + * The description of the actor in the album + */ + album_desc: string; +} + +/** + * A localization string with extra data + */ +export type ActorL10nString = { + /** + * The text with templates. + * + * Katakana marking aboce kanji in Japanese texts are stripped out + * + * {{effect}}: The effect of the CookResult + * {{effect_desc}}: The effect description of the CookResult + */ + text: string; + + /** + * Extra attribute used to determine which cook effect message + * variant to use to construct the item name + */ + attr: "" | "feminine" | "masculine" | "neuter" | "plural"; +} diff --git a/packages/research-data/src/CookEffect.ts b/packages/research-data/src/CookEffect.ts new file mode 100644 index 0000000..7816ded --- /dev/null +++ b/packages/research-data/src/CookEffect.ts @@ -0,0 +1,60 @@ +/** Schema for the CookEffect/*.yaml files */ + +import type { Locale } from "./common.ts"; + +/** + * Schema of the CookEffect/*.yaml file + */ +export type CookEffect = { + /** + * Name of the cook effect, also the file name + * + * This is the name that appears in translation files + */ + name: string; + /** This is the name that appears in Cooking/CookData.byml */ + system_name: string; + /** + * This is the associated name of the effect in the code. + * See sCookingEffects in cookManager.cpp + */ + code_name: string; + /** + * This is the value of the CookEffectId in code + */ + value: number; + /** This is the special status that this cook effect produces */ + special_status: string | null; + /** + * The localization strings of the cook effect + */ + localization: Record | null; +} + +/** Localization entry for a cook effect */ +export type CookEffectI10nEntry = { + /** The name of the effect */ + name: string; + + /** The name of the effect in feminine form */ + name_feminine: string; + + /** The name of the effect in masculine form */ + name_masculine: string; + + /** The name of the effect in neutral form */ + name_neuter: string; + + /** The name of the effect in plural form */ + name_plural: string; + /** + * Description string for each level + * Note 0th item is level 1, and so on + */ + desc: string[]; + /** + * Description string for each level, but for elixirs + * Note 0th item is level 1, and so on + */ + elixir_desc: string[]; +} diff --git a/packages/research-data/src/SpecialStatus.ts b/packages/research-data/src/SpecialStatus.ts new file mode 100644 index 0000000..53ab937 --- /dev/null +++ b/packages/research-data/src/SpecialStatus.ts @@ -0,0 +1,21 @@ +/** Schema for the SpecialStatus/*.yaml files */ +import type { Locale } from "./common.ts"; + +/** + * Schema of the SpecialStatus/*.yaml file + */ +export type SpecialStatus = { + /** Name of the special status, also the file name */ + name: string; + /** The name of the CookEffect that produces this status */ + cook_effect: string | null; + /** The name of the WeaponModifier that produces this status */ + weapon_modifier: string | null; + /** + * The localization strings of the special status + * + * The following templates are available: + * - {modifier_value} for the value of the weapon modifier + */ + localization: Record; +} diff --git a/packages/research-data/src/common.ts b/packages/research-data/src/common.ts new file mode 100644 index 0000000..7e2ff93 --- /dev/null +++ b/packages/research-data/src/common.ts @@ -0,0 +1,59 @@ +/** + * Common types in schema + */ +/** Locals supported by the game */ +export type Locale = + "en-US"| + "ja-JP"| + "de-DE"| + "es-ES"| + "it-IT"| + "fr-FR"| + "ru-RU"| + "zh-CN"| + "zh-TW"| + "ko-KR"| + "nl-NL"; + +/** Locale names used by N */ +export type LocaleNin = + "USen" | + "JPja" | + "EUde" | + "EUes" | + "EUit" | + "EUfr" | + "EUru" | + "CNzh" | + "TWzh" | + "KRko" | + "EUnl"; + +export type ToLocaleNin = + L extends "en-US" ? "USen" : + L extends "ja-JP" ? "JPja" : + L extends "de-DE" ? "EUde" : + L extends "es-ES" ? "EUes" : + L extends "it-IT" ? "EUit" : + L extends "fr-FR" ? "EUfr" : + L extends "ru-RU" ? "EUru" : + L extends "zh-CN" ? "CNzh" : + L extends "zh-TW" ? "TWzh" : + L extends "ko-KR" ? "KRko" : + L extends "nl-NL" ? "EUnl" : + never; + +export type ToLocale = + L extends "USen" ? "en-US" : + L extends "JPja" ? "ja-JP" : + L extends "EUde" ? "de-DE" : + L extends "EUes" ? "es-ES" : + L extends "EUit" ? "it-IT" : + L extends "EUfr" ? "fr-FR" : + L extends "EUru" ? "ru-RU" : + L extends "CNzh" ? "zh-CN" : + L extends "TWzh" ? "zh-TW" : + L extends "KRko" ? "ko-KR" : + L extends "EUnl" ? "nl-NL" : + never; + diff --git a/packages/runtime-wasm/.gitignore b/packages/runtime-wasm/.gitignore new file mode 100644 index 0000000..fc5bd90 --- /dev/null +++ b/packages/runtime-wasm/.gitignore @@ -0,0 +1 @@ +/pkg diff --git a/packages/runtime-wasm/Cargo.toml b/packages/runtime-wasm/Cargo.toml new file mode 100644 index 0000000..976960a --- /dev/null +++ b/packages/runtime-wasm/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "skybook-runtime-wasm" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +skybook-runtime = { path = "../runtime" } +skybook-parser = { path = "../parser" } +wasm-bindgen = { version = "0.2.99", features = ["serde", "serde-serialize"] } +teleparse = "0.0.5" + +[lib] +crate-type = ["cdylib"] + diff --git a/packages/runtime-wasm/Taskfile.yml b/packages/runtime-wasm/Taskfile.yml new file mode 100644 index 0000000..ab82d9f --- /dev/null +++ b/packages/runtime-wasm/Taskfile.yml @@ -0,0 +1,6 @@ +version: '3' + +tasks: + build: + cmds: + - wasm-pack build diff --git a/packages/runtime-wasm/src/lib.rs b/packages/runtime-wasm/src/lib.rs new file mode 100644 index 0000000..4674cf9 --- /dev/null +++ b/packages/runtime-wasm/src/lib.rs @@ -0,0 +1,13 @@ +use teleparse::Root; +use wasm_bindgen::prelude::*; +use skybook_parser::CommandInit; + +#[wasm_bindgen] +pub fn parse_script(input: String) -> String { + match CommandInit::parse(&input) { + Ok(Some(cmd)) => format!("{:?}", cmd), + Ok(None) => "no command found".to_string(), + Err(e) => format!("error: {:?}", e), + } +} + diff --git a/packages/runtime/Cargo.toml b/packages/runtime/Cargo.toml new file mode 100644 index 0000000..33927af --- /dev/null +++ b/packages/runtime/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "skybook-runtime" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +blueflame = { path = "../blueflame" } +skybook-parser = { path = "../parser" } + diff --git a/packages/runtime/src/lib.rs b/packages/runtime/src/lib.rs new file mode 100644 index 0000000..6f15c2f --- /dev/null +++ b/packages/runtime/src/lib.rs @@ -0,0 +1,114 @@ +use std::collections::{HashMap, VecDeque}; + +use blueflame::{error::Error, memory::{Memory, Proxies}}; + +mod scheduler; +use scheduler::Scheduler; + + +pub struct Runtime { + scheduler: S, + + states: Vec +} + +#[derive(Clone)] +pub struct State { + + + // named gamedata in saves + saves: HashMap, + + // gamedata in manual save + manual_save: u64, + + /// Current game state + game: Game, + + /// Current screen, only valid if game is running + screen: Screen, + + /// If inventory/dialog screen is activated manually, + /// so auto-scoping will be disabled until returned to overworld screen + is_manual_scope: bool, + + /// If auto scope is enabled at all + enable_auto_scope: bool, +} + +#[derive(Clone)] +pub enum Game { + /// Game is not booted + Off, + /// Game is running + Running(GameState), + /// Game has crashed (must manually reboot) + Crashed(Error) // TODO: more crash info (dump, stack trace, etc) +} + +#[derive(Clone)] +pub enum Screen { + /// In the overworld, no additional screens + Overworld, + /// In the inventory screen + Inventory, + /// In an unknown dialog (could be sell/statue, or other) + Dialog, + /// In sell dialog + DialogSell, + /// In statue dialog + DialogStatue, +} + +/// State available when the game is running +#[derive(Clone)] +pub struct GameState { + // gamedata TriggerParam* + gamedata: u64, + // memory states + // + /// Full process memory + memory: Memory, + + /// Proxy objects in memory + proxies: Proxies, + + /// Current actors in the overworld + /// TODO: make this copy on write and Arc + ovwd_weapon: Option, + ovwd_shield: Option, + ovwd_bow: Option, + ovwd_armor_head: Option, + ovwd_armor_upper: Option, + ovwd_armor_lower: Option, + + ovwd_dropped_materials: VecDeque, + ovwd_dropped_equipments: VecDeque, + + ovwd_holding_materials: VecDeque, + + entangled_slots: Vec, +} + +#[derive(Clone)] +pub struct ActorState { + pub name: String, + pub life: u32, + pub modifier_bits: u32, + pub modifier_value: i32, +} + +impl GameState { + + // just a placeholder + // probably some kind of macro to generate these + pub async fn get_item(mut self, scheduler: impl Scheduler, item: &str) -> Result { + scheduler.run_on_core(move |p| { + let core = p.attach(&mut self.memory, &mut self.proxies); + // todo: real function + core.pmdm_item_get(item, 0, 0)?; + + Ok(self) + }).await + } +} diff --git a/packages/runtime/src/scheduler/mod.rs b/packages/runtime/src/scheduler/mod.rs new file mode 100644 index 0000000..6ab7149 --- /dev/null +++ b/packages/runtime/src/scheduler/mod.rs @@ -0,0 +1,9 @@ +use blueflame::processor::Processor; + +pub trait Scheduler: Clone { + /// Future type for this scheduler + type Future: std::future::Future + Send + 'static; + + /// Schedule a task a on a processor + fn run_on_core T>(&self, f: F) -> Self::Future; +} diff --git a/sim/parser/Cargo.toml b/sim/parser/Cargo.toml deleted file mode 100644 index 49de6f4..0000000 --- a/sim/parser/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "ist-parser" -version = "0.0.0" -edition = "2021" -publish = false - -[dependencies] -teleparse = "0.0.4" -logos = "0.14.1" # not needed after teleparse fix the bug diff --git a/sim/parser/src/lib.rs b/sim/parser/src/lib.rs deleted file mode 100644 index de66599..0000000 --- a/sim/parser/src/lib.rs +++ /dev/null @@ -1,182 +0,0 @@ -use teleparse::{derive_lexicon, derive_syntax, tp}; - -pub fn test_message(n: u64) -> String { - format!("Hello from Rust! You passed in {}", n) -} - -#[derive_lexicon] -pub enum TT { - #[teleparse(terminal( - SymLAngle = "<", - SymRAngle = ">", - SymLParen = "(", - SymRParen = ")", - SymLBracket = "[", - SymRBracket = "]", - SymLBrace = "{", - SymRBrace = "}", - SymEqual = "=", - SymColon = ":", - SymComma = ",", - SymSemi = ";", - ))] - Symbol, - - #[teleparse(regex(r"\d+"), terminal(Number))] - Number, - #[teleparse(regex(r"0x[0-9a-fA-F]+"), terminal(HexNumber))] - HexNumber, - - #[teleparse( - terminal( - CmdInit = "init", - CmdInitGdt = "init-gdt", - - CmdGet = "get", - CmdPickUp = "pick-up", - CmdBuy = "buy", - CmdCook = "cook", - - CmdEat = "eat", - CmdSell = "sell", - CmdEatAll = "eat-all", // tyupe - CmdSellAll = "sell-all", //type - CmdDropAll = "drop-all", //type - - CmdHold = "hold", - CmdUnhold = "unhold", - CmdHoldSmuggle = "hold-smuggle", - CmdHoldAttach = "hold-attach", - CmdDrop = "drop", - CmdPutAside = "put-aside", - CmdDnp = "dnp", - - CmdRoast = "roast", - CmdBoil = "boil", - CmdFreeze = "freeze", - - CmdEquip = "equip", - CmdUnequip = "unequip", // type - CmdUnequipThe = "unequip-the", // item - CmdShoot = "shoot-arrow", - - CmdSort = "sort", // type - // - CmdSave = "save", - CmdSaveAs = "save-as", - CmdReload = "reload", - - CmdCloseGame = "close-game", - CmdNewGame = "new-game", - ) - )] - Command, - - #[teleparse(terminal(AmtAll = "all", AmtInfinite = "infinite"))] - Amount, - - #[teleparse(terminal( - KwFrom = "from", - KwSlot = "slot", - ))] - Keyword, - - #[teleparse(regex(r"[-a-zA-Z]+"), terminal(Word))] - Word, - - Variable, - Name, - Type, -} - -#[derive_syntax] -#[teleparse(root)] -pub struct CommandInit { - pub cmd: CmdInit, - pub items: NumberedItemList, -} - -#[derive_syntax] -pub enum NumberedItemList { - Single(Item), - List(tp::Vec), -} - -#[derive_syntax] -pub struct NumberedItem { - pub num: Num, - pub item: Item, -} - -#[derive_syntax] -pub struct NumberedOrAllItem { - pub num: NumOrAll, - pub item: Item, -} - -#[derive_syntax] -pub struct NumberedOrInfiniteItem { - pub num: NumOrInfinite, - pub item: Item, -} - -#[derive_syntax] -pub struct Item { - #[teleparse(semantic(Name))] - pub name: tp::Nev, - pub meta: tp::Option, -} - -#[derive_syntax] -pub struct ItemMeta { - pub open: SymLBracket, - pub entries: tp::Punct, - pub close: SymRBracket, -} - -#[derive_syntax] -pub struct ItemMetaKeyValue { - #[teleparse(semantic(Variable))] - pub key: Word, - pub value: tp::Option -} - -#[derive_syntax] -pub struct ItemMetaValue { - pub sep: MetaSep, - pub value: WordOrNum, -} - -#[derive_syntax] -pub enum WordOrNum { - Word(Word), - Number(Number), - HexNumber(HexNumber), -} - -#[derive_syntax] -pub enum Num { - Number(Number), - HexNumber(HexNumber), -} - -#[derive_syntax] -pub enum NumOrAll { - All(AmtAll), - Number(Number), - HexNumber(HexNumber), -} - -#[derive_syntax] -pub enum NumOrInfinite { - Infinite(AmtInfinite), - Number(Number), - HexNumber(HexNumber), -} - -#[derive_syntax] -pub enum MetaSep { - Colon(SymColon), - Equal(SymEqual), -} - diff --git a/sim/runtime/Cargo.toml b/sim/runtime/Cargo.toml deleted file mode 100644 index 0d9fc92..0000000 --- a/sim/runtime/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "ist-runtime" -version = "0.0.0" -edition = "2021" -publish = false - -[dependencies] -ist-parser = { path = "../parser" } - diff --git a/sim/runtime/src/lib.rs b/sim/runtime/src/lib.rs deleted file mode 100644 index 49b3ed2..0000000 --- a/sim/runtime/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ - -pub fn get_message() -> String { - ist_parser::test_message(42) -} -