diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f9b44f4..1aa8075c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,25 +4,39 @@ on: types: [created] jobs: - release: - name: release ${{ matrix.target }} - runs-on: ubuntu-latest + build-tauri: strategy: fail-fast: false matrix: - include: - - target: x86_64-pc-windows-gnu - archive: zip - - target: x86_64-unknown-linux-musl - archive: tar.gz tar.xz - - target: x86_64-apple-darwin - archive: zip + platform: [macos-latest, ubuntu-20.04, windows-latest] + + runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@master - - name: Compile and release - uses: rust-build/rust-build.action@v1.3.2 + - uses: actions/checkout@v2 + - name: setup node + uses: actions/setup-node@v1 + with: + node-version: 16 + - name: install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-20.04' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + - name: install app dependencies and build it + run: npm i && npm run build + + - name: Get release + id: get_release + uses: bruceadams/get-release@v1.3.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - RUSTTARGET: ${{ matrix.target }} - ARCHIVE_TYPES: ${{ matrix.archive }} + releaseId: ${{ steps.get_release.outputs.id }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..4ab51f24 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,35 @@ +name: "test-on-pr" +on: [pull_request] + +jobs: + test-tauri: + strategy: + fail-fast: false + matrix: + platform: [macos-latest, ubuntu-20.04, windows-latest] + + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + - name: setup node + uses: actions/setup-node@v1 + with: + node-version: 16 + - name: install Rust stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-20.04' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + - name: install app dependencies and build it + run: npm i && npm run build + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/upload-artifact@v3 + with: + name: bundle + path: src-tauri/target/release/bundle/ diff --git a/.gitignore b/.gitignore index 22d35163..b93eddfb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,26 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock +node_modules +dist +dist-ssr +*.local -# These are backup files generated by rustfmt -**/*.rs.bk +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? - -# Added by cargo - -/target +target diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..24d7cc6d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] +} diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 8fa16ff3..00000000 --- a/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "pocket-sync" -version = "0.2.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -chrono = "0.4.22" -clap = { version = "4.0.18", features = ["derive"] } -filetime = "0.2.18" -suppaftp = "4.5.2" -question = "0.2.2" -serde = { version = "1.0.147", features = ["derive"] } -serde_json = "1.0.87" -walkdir = "2.3.2" diff --git a/README.md b/README.md index a4c9ccce..087a6886 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,34 @@ # pocket-sync -A tool for syncing the Analogue Pocket (initially with MiSTer) -[![asciicast](https://asciinema.org/a/VnRRsQj8BOikkHi3PKgo4OeWI.svg)](https://asciinema.org/a/VnRRsQj8BOikkHi3PKgo4OeWI?autoplay=1) +A Windows / Mac / Linx GUI to do _stuff_ with the Analogue Pocket. +![The Cores List](./readme_images/cores_list.png) -__WARNING__ this is a _very_ early release - please don't use it without having backed up your saves. -I recommend backing up via `zip -r saves_backup.zip saves` on the MiSTer & `zip -r saves_backup.zip Saves` on the Pocket. +Features: -- There's some inherent issues comparing last modified dates between different systems & with this you've got 3 (the Pocket, the MiSTer, and your PC) - so don't expect this to be accurate within a single day & I'd recommend against running the merge process twice in one day -- this might be fixed later if I can narrow down how the MiSTer, Pocket etc store timestamps. +- Browse & install cores +- Export corrected & upscalled screenshots +- Backup save files +- Quick links to open game file folders -- If you see a bunch of Pocket saves with the timestamp `2020-01-01 23:00:00 +00:00` they were probably saved on an older Pocket firmware that wasn't doing timestamps. +## Roadmap -- If there's a save which is _only_ on the MiSTer it'll be moved to the _root folder_ on the Pocket, if the rom's in a nested folder this'll mean the save won't get picked up. +### Soon -- Some cores do double duty on the MiSTer (e.g. `GAMEBOY` does GB & GBC), for these cores if there isn't a Pocket save already they'll be put somewhere (hopefully) sensible (`GameGear` might be an issue though since it's in with `SMS` on the MiSTer) +- Installing / Checking for firmware updates +- Hopefully get the saves backups working how I'd planned -- The ROM name must match _exactly_ for it to be picked up as a save, this might cause issues for NEOGEO. +### Longer term -## Usage +- Add back MiSTer save file sync (don't really want to touch it if there's a chance I'll clopper MiSTer files with a bunch of incompatiable Genesis saves) -- Grab the latest release for your OS from the releases section -> -- You'll probably need to jump through the "Unidentified Developer" thing (well, on Mac anyway) -- Your MiSTer will need to be on and have FTP enabled (on the default port, 21) -- (Probably a good time to back up your saves just incase) -- Run `./pocket-sync [path-to-pocket-SD-card] --host-mister [mister IP or hostname]` -- If you've changed the user / password on your MiSTer you'll need to use `--user-mister [name]` / `--password-mister [password]` -- It'll add a `pocket_sync.json` that (currently) just contains the timestamp of the last run so the program knows not to bother with things that've been synced already -- It'll merge the saves by these rules: - - If both devices have the save & they're both older than the last-run timestamp **skip** - - If only one device has the save, **copies it to both** - - If one device has a save newer than the last-run time & the other is older **copies newer over older** - - If both devices have saves newer than the last-run time **allows you to pick the Pocket save, the MiSTer save, or to skip** -## Roadmap +## FAQs + +### Donations? + +Nah, I'm alright - you should donate to the folks porting / building cores over though. + +## Thanks to -- [x] CLI for syncing saves with a MiSTer over FTP -- [ ] GUI (Windows / Mac / Linux) -- [ ] Library browser / editor in GUI -- [ ] Auto-updating GUI -- [ ] Core Updater in GUI (maybe) -- [ ] GUI for core updator showing release notes etc +- [The OpenFPGA Cores Inventory supplies a bunch of the data used in the app](https://github.com/joshcampbell191/openfpga-cores-inventory) +- [This recreation of the Analogue OS font](https://github.com/AbFarid/analogue-os-font) diff --git a/app-icon.png b/app-icon.png new file mode 100644 index 00000000..a697e533 Binary files /dev/null and b/app-icon.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..5d85875c --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + Pocket Sync + + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..aee35089 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5820 @@ +{ + "name": "pocket-sync", + "version": "2.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "pocket-sync", + "version": "2.0.0", + "dependencies": { + "@react-three/drei": "^9.40.0", + "@react-three/fiber": "^8.9.1", + "@tauri-apps/api": "^1.1.0", + "@types/three": "^0.146.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-markdown": "^8.0.3", + "recoil": "^0.7.6", + "remark-gfm": "^3.0.1", + "three": "^0.146.0" + }, + "devDependencies": { + "@tauri-apps/cli": "^1.1.0", + "@types/node": "^18.7.10", + "@types/react": "^18.0.15", + "@types/react-dom": "^18.0.6", + "@vitejs/plugin-react": "^2.0.0", + "postcss-nesting": "^10.2.0", + "typescript": "^4.6.4", + "vite": "^3.0.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", + "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "dependencies": { + "regenerator-runtime": "^0.13.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.4.1.tgz", + "integrity": "sha512-wNDw9Rh6dPJKH275er8nijuDIpTcG2GjQANjnG8RaeGkZ3JN99+u6HRtnjKhjoi4NY9rg+udHChHQSskZtlkPw==", + "dependencies": { + "@chevrotain/gast": "10.4.1", + "@chevrotain/types": "10.4.1", + "lodash": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.4.1.tgz", + "integrity": "sha512-HRv66QVbmC7eb/ppwsPCfNH4oZ/VV+thuMZILm7A7W6Q5M0tqiZv0ecdiB8hydmPO8je0aSrXEOCcaA6fuXc3Q==", + "dependencies": { + "@chevrotain/types": "10.4.1", + "lodash": "4.17.21" + } + }, + "node_modules/@chevrotain/types": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.4.1.tgz", + "integrity": "sha512-J8iyZNn/RGYWSyNJdGd3QI01gKFUx4mCSM0+vEqmIw9TXFlxj1IsHteXFahtezSHjgMtBTqWn6hb2YxCLjpHVg==" + }, + "node_modules/@chevrotain/utils": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.4.1.tgz", + "integrity": "sha512-vPIgzES8QhHMchb5UaQ4V/c9xmoaECN+4EXpuhWE+pu3LXJUUtAwDn/SEKFgtyiRo269Hxv3b0NbPlQfH0jeVA==" + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", + "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", + "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@react-spring/animated": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.5.5.tgz", + "integrity": "sha512-glzViz7syQ3CE6BQOwAyr75cgh0qsihm5lkaf24I0DfU63cMm/3+br299UEYkuaHNmfDfM414uktiPlZCNJbQA==", + "dependencies": { + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.5.5.tgz", + "integrity": "sha512-shaJYb3iX18Au6gkk8ahaF0qx0LpS0Yd+ajb4asBaAQf6WPGuEdJsbsNSgei1/O13JyEATsJl20lkjeslJPMYA==", + "dependencies": { + "@react-spring/animated": "~9.5.5", + "@react-spring/rafz": "~9.5.5", + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.5.5.tgz", + "integrity": "sha512-F/CLwB0d10jL6My5vgzRQxCNY2RNyDJZedRBK7FsngdCmzoq3V4OqqNc/9voJb9qRC2wd55oGXUeXv2eIaFmsw==" + }, + "node_modules/@react-spring/shared": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.5.5.tgz", + "integrity": "sha512-YwW70Pa/YXPOwTutExHZmMQSHcNC90kJOnNR4G4mCDNV99hE98jWkIPDOsgqbYx3amIglcFPiYKMaQuGdr8dyQ==", + "dependencies": { + "@react-spring/rafz": "~9.5.5", + "@react-spring/types": "~9.5.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.5.5.tgz", + "integrity": "sha512-9kTIaSceqFIl5EIrdwM7Z53o5I+9BGNVzbp4oZZYMao+GMAWOosnlQdDG5GeqNsIqfW9fZCEquGqagfKAxftcA==", + "dependencies": { + "@react-spring/animated": "~9.5.5", + "@react-spring/core": "~9.5.5", + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "three": ">=0.126" + } + }, + "node_modules/@react-spring/types": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.5.5.tgz", + "integrity": "sha512-7I/qY8H7Enwasxr4jU6WmtNK+RZ4Z/XvSlDvjXFVe7ii1x0MoSlkw6pD7xuac8qrHQRm9BTcbZNyeeKApYsvCg==" + }, + "node_modules/@react-three/drei": { + "version": "9.40.0", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.40.0.tgz", + "integrity": "sha512-v+7l62c7BIXS172E1TiEOeXXpZnfoJNsdjZK5h0TxKVXsbhs5t6rMAlDKhgWbZ96rDzgNrSIPv+GMzlG/rkFdQ==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@react-spring/three": "^9.3.1", + "@use-gesture/react": "^10.2.0", + "detect-gpu": "^4.0.36", + "glsl-noise": "^0.0.0", + "lodash.clamp": "^4.0.3", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "meshline": "^2.0.4", + "react-composer": "^5.0.3", + "react-merge-refs": "^1.1.0", + "stats.js": "^0.17.0", + "suspend-react": "^0.0.8", + "three-mesh-bvh": "^0.5.15", + "three-stdlib": "^2.17.3", + "troika-three-text": "^0.46.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.13" + }, + "peerDependencies": { + "@react-three/fiber": ">=8.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "three": ">=0.137" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.9.1.tgz", + "integrity": "sha512-xRMO9RGp0DkxSFu5BmmkjCxJ4r0dEpLobtxXdZwI0h2rZZaCnkPM5zThRN8xaZNbZhzRSVICeNOFaZltr9xFyQ==", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.26.7", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "react-use-measure": "^2.1.1", + "scheduler": "^0.21.0", + "suspend-react": "^0.0.8", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-gl": ">=11.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "react-native": ">=0.64", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@tauri-apps/api": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz", + "integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==", + "engines": { + "node": ">= 14.6.0", + "npm": ">= 6.6.0", + "yarn": ">= 1.19.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.0.tgz", + "integrity": "sha512-DgUnk4p/atWHq2HUx9Vt+/LuRsx4iFlkzdZIUxtFWvpcZih2k0TzmHJbrhM1evh1/7a+SqiwDawmyf3Hz1HxXA==", + "dev": true, + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "1.2.0", + "@tauri-apps/cli-darwin-x64": "1.2.0", + "@tauri-apps/cli-linux-arm-gnueabihf": "1.2.0", + "@tauri-apps/cli-linux-arm64-gnu": "1.2.0", + "@tauri-apps/cli-linux-arm64-musl": "1.2.0", + "@tauri-apps/cli-linux-x64-gnu": "1.2.0", + "@tauri-apps/cli-linux-x64-musl": "1.2.0", + "@tauri-apps/cli-win32-ia32-msvc": "1.2.0", + "@tauri-apps/cli-win32-x64-msvc": "1.2.0" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-f3LR2RvTU2ulxYdK9Nc3vKaSpDChu52pz0BMWNrSs3dxs4WTVioie98Ufz+GorifkUp3sYXcJte3HzX6wH/QxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.0.tgz", + "integrity": "sha512-m07QZaAZCtyobrjddfz/Rxf9GGutnBOpRMbNqVqCk0qKRJzHG1fIsLqkgZh6+qPv0zHpu7xi/FPcqTec72Cp8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-Id9eF1JtthZRFVtXAAVtSlI3uMT8cJ7LYmCSIl3mAXEUeaPBxnUs1i9X6/J+2Ho3yLEuuOxJ7PaJd+4v8wnEeg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-NtfPkkpeMPl+i/tB/Fc8ST2rKO2vV8int/RkOvNGLCkhWcl4sbzKBol7tc4q8c8h0X7FXDcF1l/EOuGsZUAA5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-tz+mOOVsy/TMdq2WJVIJl/iwW3OCWCyD5Fls3fhyJ4XpLfjn4G+C+oU0awXD/0se0ko81aq4D+r8eDx6oBRi0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-FH/wU+OWZjRQvrq/oequScr72I84XgOuRuMEpt/GqGD341cBJ8ithpoyzuiKsvjS6K0qMyRFzy3eyhQ7gwX+4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-nLg30aBT9fI83sjIqaGPN7twbtE5LJy2DbKzxIlw59F+GT8HBdiM/2mZdTLB3AQb52yVHuGB1TVtWDsl0JHqCA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.0.tgz", + "integrity": "sha512-eXtgIgY0fawgcOuUjH8Y6PxwPxbK87Zl9XmA7Q0m58T7pIz+gcbgvtH8Bb+liYHoRYItIhQxVm+ui7Y59rI7Cg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-egyM66R05AIbkaUDptpHurFTIYp3VM4H5OrRd3O2b0oXf8SoiXiyrHbQsHVHHDYyytKmwkdNqjdy+Vev/Vq25Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", + "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/react": { + "version": "18.0.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.25.tgz", + "integrity": "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.8.tgz", + "integrity": "sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/three": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.146.0.tgz", + "integrity": "sha512-75AgysUrIvTCB054eQa2pDVFurfeFW8CrMQjpzjt3yHBfuuknoSvvsESd/3EhQxPrz9si3+P0wiDUVsWUlljfA==", + "dependencies": { + "@types/webxr": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "node_modules/@types/webxr": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.0.tgz", + "integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==" + }, + "node_modules/@use-gesture/core": { + "version": "10.2.22", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.22.tgz", + "integrity": "sha512-Ek0JZFYfk+hicLmoG094gm3YOuDMBNckHb988e59YOZoAkETT8dQSzT+g3QkSHSiP1m5wFXAGPSgxvOuwvGKHQ==" + }, + "node_modules/@use-gesture/react": { + "version": "10.2.22", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.22.tgz", + "integrity": "sha512-ECo7ig16SxBE06ENIURO1woKEB6TC8qY3a0rugJjQ2f1o0Tj28xS/eYNyJuqzQB5YT0q5IrF7ZFpbx1p/5ohYA==", + "dependencies": { + "@use-gesture/core": "10.2.22" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-2.2.0.tgz", + "integrity": "sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-jsx": "^7.19.0", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-jsx-self": "^7.18.6", + "@babel/plugin-transform-react-jsx-source": "^7.19.6", + "magic-string": "^0.26.7", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^3.0.0" + } + }, + "node_modules/@webgpu/glslang": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" + }, + "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/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/bidi-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.2.tgz", + "integrity": "sha512-rzSy/k7WdX5zOyeHHCOixGXbCHkyogkxPKL2r8QtzHmVQDiWCXUWa18bLdMWT9CYMLOYTjWpTHawuev2ouYJVw==", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.4.1.tgz", + "integrity": "sha512-1y4vnssauVmrrP5MBaJ6DZvsv3BpXLlKVNK5S52fTGQHqg09qxMDBAz0wZbb04Ovc1pBCA4obcCjOlRioIV+cA==", + "dependencies": { + "@chevrotain/cst-dts-gen": "10.4.1", + "@chevrotain/gast": "10.4.1", + "@chevrotain/types": "10.4.1", + "@chevrotain/utils": "10.4.1", + "lodash": "4.17.21", + "regexp-to-ast": "0.5.0" + } + }, + "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/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-gpu": { + "version": "4.0.48", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-4.0.48.tgz", + "integrity": "sha512-qrJTrCeYG/5aaMaqHlbTZu3cTZB/TZJ/ZbDDEb712FMe5irqjGwp2fyG4ag+y19f4QGKg55dQXf8IuKo+oCmRw==", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/draco3d": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.5.tgz", + "integrity": "sha512-JVuNV0EJzD3LBYhGyIXJLeBID/EVtmFO1ZNhAYflTgiMiAJlbhXQmRRda/azjc8MRVMHh0gqGhiqHUo5dIXM8Q==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", + "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.13", + "@esbuild/linux-loong64": "0.15.13", + "esbuild-android-64": "0.15.13", + "esbuild-android-arm64": "0.15.13", + "esbuild-darwin-64": "0.15.13", + "esbuild-darwin-arm64": "0.15.13", + "esbuild-freebsd-64": "0.15.13", + "esbuild-freebsd-arm64": "0.15.13", + "esbuild-linux-32": "0.15.13", + "esbuild-linux-64": "0.15.13", + "esbuild-linux-arm": "0.15.13", + "esbuild-linux-arm64": "0.15.13", + "esbuild-linux-mips64le": "0.15.13", + "esbuild-linux-ppc64le": "0.15.13", + "esbuild-linux-riscv64": "0.15.13", + "esbuild-linux-s390x": "0.15.13", + "esbuild-netbsd-64": "0.15.13", + "esbuild-openbsd-64": "0.15.13", + "esbuild-sunos-64": "0.15.13", + "esbuild-windows-32": "0.15.13", + "esbuild-windows-64": "0.15.13", + "esbuild-windows-arm64": "0.15.13" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", + "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", + "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", + "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", + "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", + "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", + "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", + "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", + "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", + "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", + "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", + "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", + "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", + "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", + "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", + "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", + "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", + "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", + "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", + "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", + "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-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/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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/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/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==" + }, + "node_modules/hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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/hast-util-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", + "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/its-fine": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.0.6.tgz", + "integrity": "sha512-VZJZPwVT2kxe5KQv+TxCjojfLiUIut8zXDNLTxcM7gJ/xQ/bSPk5M0neZ+j3myy45KKkltY1mm1jyJgx3Fxsdg==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.0.tgz", + "integrity": "sha512-5cjk9ottZAj7eaTsqzPUIlrVbh3hBAO2YaEL1rkjHKB3xNAId7oU8GhzvAX+gfmlfoxTwJnBjPxEHyxkEA1Ffg==", + "dependencies": { + "@types/react": "*" + } + }, + "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/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/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ktx-parse": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.4.5.tgz", + "integrity": "sha512-MK3FOody4TXbFf8Yqv7EBbySw7aPvEcPX++Ipt6Sox+/YMFvR5xaTyhfNSk1AEmMy+RYIw81ctN4IMxCB8OAlg==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.clamp": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lodash.clamp/-/lodash.clamp-4.0.3.tgz", + "integrity": "sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==" + }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, + "node_modules/longest-streak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", + "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/magic-string": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", + "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/markdown-table": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", + "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-definitions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", + "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.1.tgz", + "integrity": "sha512-SobxkQXFAdd4b5WmEakmkVoh18icjQRxGy5OWTCzgsLRm1Fu/KCtwD1HIQSsmq5ZRjVH0Ehwg6/Fn3xIUk+nKw==", + "dependencies": { + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz", + "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==", + "dependencies": { + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz", + "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==", + "dependencies": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz", + "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.2.tgz", + "integrity": "sha512-T/4DVHXcujH6jx1yqpcAYYwd+z5lAYMw4Ls6yhTfbMMtCt0PHY4gEfhW9+lKsLBtyhUGKRIzcUA2FATVqnvPDA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", + "dependencies": { + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz", + "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", + "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/meshline": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-2.0.4.tgz", + "integrity": "sha512-Jh6DJl/zLqA4xsKvGv5950jr2ukyXQE1wgxs8u94cImHrvL6soVIggqjP+2hVHZXGYaKnWszhtjuCbKNeQyYiw==", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz", + "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz", + "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==", + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz", + "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz", + "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz", + "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==", + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz", + "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mmd-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", + "dependencies": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", + "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" + }, + "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==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/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==" + }, + "node_modules/property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-composer": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", + "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", + "dependencies": { + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-markdown": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", + "integrity": "sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/react-merge-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", + "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "dependencies": { + "debounce": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + } + }, + "node_modules/recoil": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.6.tgz", + "integrity": "sha512-hsBEw7jFdpBCY/tu2GweiyaqHKxVj6EqF2/SfrglbKvJHhpN57SANWvPW+gE90i3Awi+A5gssOd3u+vWlT+g7g==", + "dependencies": { + "hamt_plus": "1.0.2" + }, + "peerDependencies": { + "react": ">=16.13.1" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" + }, + "node_modules/remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==" + }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, + "node_modules/style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "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/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/suspend-react": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.0.8.tgz", + "integrity": "sha512-ZC3r8Hu1y0dIThzsGw0RLZplnX9yXwfItcvaIzJc2VQVi8TGyGDlu92syMB5ulybfvGLHAI5Ghzlk23UBPF8xg==", + "peerDependencies": { + "react": ">=17.0" + } + }, + "node_modules/three": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.146.0.tgz", + "integrity": "sha512-1lvNfLezN6OJ9NaFAhfX4sm5e9YCzHtaRgZ1+B4C+Hv6TibRMsuBAM5/wVKzxjpYIlMymvgsHEFrrigEfXnb2A==" + }, + "node_modules/three-mesh-bvh": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.5.18.tgz", + "integrity": "sha512-lJQkt4A+pfHMf8Pbyqm5UiIBoVtp3cuy5rrTpuhIaJlbAobJW3/uQxJVZKiHaGi1Bs+5Svb+T8xIS17EqjG2ZA==", + "peerDependencies": { + "three": ">= 0.123.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.17.4", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.17.4.tgz", + "integrity": "sha512-Xh9+B/1RL0YXRjWgLilbK/5qL7hVOWMF5sQ1seKqGvR4svNvQPU+vCZkL2sUaZ0usc/C3FpyGTuwbqo+eW444Q==", + "dependencies": { + "@babel/runtime": "^7.16.7", + "@types/offscreencanvas": "^2019.6.4", + "@webgpu/glslang": "^0.0.15", + "chevrotain": "^10.1.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "ktx-parse": "^0.4.5", + "mmd-parser": "^1.0.4", + "opentype.js": "^1.3.3", + "potpack": "^1.0.1", + "zstddec": "^0.0.2" + }, + "peerDependencies": { + "three": ">=0.122.0" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "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/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/troika-three-text": { + "version": "0.46.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.46.4.tgz", + "integrity": "sha512-Qsv0HhUKTZgSmAJs5wvO7YlBoJSP9TGPLmrg+K9pbQq4lseQdcevbno/WI38bwJBZ/qS56hvfqEzY0zUEFzDIw==", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.46.0", + "troika-worker-utils": "^0.46.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.103.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.46.0.tgz", + "integrity": "sha512-llHyrXAcwzr0bpg80GxsIp73N7FuImm4WCrKDJkAqcAsWmE5pfP9+Qzw+oMWK1P/AdHQ79eOrOl9NjyW4aOw0w==", + "peerDependencies": { + "three": ">=0.103.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.46.0.tgz", + "integrity": "sha512-bzOx5f2ZBxkFhXtIvDJlLn2AI3bzCkGVbCndl/2dL5QZrwHEKl45OEIilCxYQQWJG1rEbOD9O80tMjoYjw19OA==" + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.3.tgz", + "integrity": "sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.15.9", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" + }, + "node_modules/zstddec": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" + }, + "node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.3.tgz", + "integrity": "sha512-dn/sDAIuRCsXGnBD4P+SA6nv7Y54HQZjC4SPL8PToU3714zu7wSEc1129D/i0+vvjRfOlFo4Zqrpwj+Zhcykhw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "dev": true + }, + "@babel/core": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", + "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "dev": true + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dev": true, + "requires": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/runtime": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", + "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "requires": { + "regenerator-runtime": "^0.13.10" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@chevrotain/cst-dts-gen": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.4.1.tgz", + "integrity": "sha512-wNDw9Rh6dPJKH275er8nijuDIpTcG2GjQANjnG8RaeGkZ3JN99+u6HRtnjKhjoi4NY9rg+udHChHQSskZtlkPw==", + "requires": { + "@chevrotain/gast": "10.4.1", + "@chevrotain/types": "10.4.1", + "lodash": "4.17.21" + } + }, + "@chevrotain/gast": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.4.1.tgz", + "integrity": "sha512-HRv66QVbmC7eb/ppwsPCfNH4oZ/VV+thuMZILm7A7W6Q5M0tqiZv0ecdiB8hydmPO8je0aSrXEOCcaA6fuXc3Q==", + "requires": { + "@chevrotain/types": "10.4.1", + "lodash": "4.17.21" + } + }, + "@chevrotain/types": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.4.1.tgz", + "integrity": "sha512-J8iyZNn/RGYWSyNJdGd3QI01gKFUx4mCSM0+vEqmIw9TXFlxj1IsHteXFahtezSHjgMtBTqWn6hb2YxCLjpHVg==" + }, + "@chevrotain/utils": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.4.1.tgz", + "integrity": "sha512-vPIgzES8QhHMchb5UaQ4V/c9xmoaECN+4EXpuhWE+pu3LXJUUtAwDn/SEKFgtyiRo269Hxv3b0NbPlQfH0jeVA==" + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@esbuild/android-arm": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", + "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", + "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", + "dev": true, + "optional": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@react-spring/animated": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.5.5.tgz", + "integrity": "sha512-glzViz7syQ3CE6BQOwAyr75cgh0qsihm5lkaf24I0DfU63cMm/3+br299UEYkuaHNmfDfM414uktiPlZCNJbQA==", + "requires": { + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + } + }, + "@react-spring/core": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.5.5.tgz", + "integrity": "sha512-shaJYb3iX18Au6gkk8ahaF0qx0LpS0Yd+ajb4asBaAQf6WPGuEdJsbsNSgei1/O13JyEATsJl20lkjeslJPMYA==", + "requires": { + "@react-spring/animated": "~9.5.5", + "@react-spring/rafz": "~9.5.5", + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + } + }, + "@react-spring/rafz": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.5.5.tgz", + "integrity": "sha512-F/CLwB0d10jL6My5vgzRQxCNY2RNyDJZedRBK7FsngdCmzoq3V4OqqNc/9voJb9qRC2wd55oGXUeXv2eIaFmsw==" + }, + "@react-spring/shared": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.5.5.tgz", + "integrity": "sha512-YwW70Pa/YXPOwTutExHZmMQSHcNC90kJOnNR4G4mCDNV99hE98jWkIPDOsgqbYx3amIglcFPiYKMaQuGdr8dyQ==", + "requires": { + "@react-spring/rafz": "~9.5.5", + "@react-spring/types": "~9.5.5" + } + }, + "@react-spring/three": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.5.5.tgz", + "integrity": "sha512-9kTIaSceqFIl5EIrdwM7Z53o5I+9BGNVzbp4oZZYMao+GMAWOosnlQdDG5GeqNsIqfW9fZCEquGqagfKAxftcA==", + "requires": { + "@react-spring/animated": "~9.5.5", + "@react-spring/core": "~9.5.5", + "@react-spring/shared": "~9.5.5", + "@react-spring/types": "~9.5.5" + } + }, + "@react-spring/types": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.5.5.tgz", + "integrity": "sha512-7I/qY8H7Enwasxr4jU6WmtNK+RZ4Z/XvSlDvjXFVe7ii1x0MoSlkw6pD7xuac8qrHQRm9BTcbZNyeeKApYsvCg==" + }, + "@react-three/drei": { + "version": "9.40.0", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.40.0.tgz", + "integrity": "sha512-v+7l62c7BIXS172E1TiEOeXXpZnfoJNsdjZK5h0TxKVXsbhs5t6rMAlDKhgWbZ96rDzgNrSIPv+GMzlG/rkFdQ==", + "requires": { + "@babel/runtime": "^7.11.2", + "@react-spring/three": "^9.3.1", + "@use-gesture/react": "^10.2.0", + "detect-gpu": "^4.0.36", + "glsl-noise": "^0.0.0", + "lodash.clamp": "^4.0.3", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "meshline": "^2.0.4", + "react-composer": "^5.0.3", + "react-merge-refs": "^1.1.0", + "stats.js": "^0.17.0", + "suspend-react": "^0.0.8", + "three-mesh-bvh": "^0.5.15", + "three-stdlib": "^2.17.3", + "troika-three-text": "^0.46.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.13" + } + }, + "@react-three/fiber": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.9.1.tgz", + "integrity": "sha512-xRMO9RGp0DkxSFu5BmmkjCxJ4r0dEpLobtxXdZwI0h2rZZaCnkPM5zThRN8xaZNbZhzRSVICeNOFaZltr9xFyQ==", + "requires": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.26.7", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "react-use-measure": "^2.1.1", + "scheduler": "^0.21.0", + "suspend-react": "^0.0.8", + "zustand": "^3.7.1" + }, + "dependencies": { + "scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "requires": { + "loose-envify": "^1.1.0" + } + } + } + }, + "@tauri-apps/api": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz", + "integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==" + }, + "@tauri-apps/cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.0.tgz", + "integrity": "sha512-DgUnk4p/atWHq2HUx9Vt+/LuRsx4iFlkzdZIUxtFWvpcZih2k0TzmHJbrhM1evh1/7a+SqiwDawmyf3Hz1HxXA==", + "dev": true, + "requires": { + "@tauri-apps/cli-darwin-arm64": "1.2.0", + "@tauri-apps/cli-darwin-x64": "1.2.0", + "@tauri-apps/cli-linux-arm-gnueabihf": "1.2.0", + "@tauri-apps/cli-linux-arm64-gnu": "1.2.0", + "@tauri-apps/cli-linux-arm64-musl": "1.2.0", + "@tauri-apps/cli-linux-x64-gnu": "1.2.0", + "@tauri-apps/cli-linux-x64-musl": "1.2.0", + "@tauri-apps/cli-win32-ia32-msvc": "1.2.0", + "@tauri-apps/cli-win32-x64-msvc": "1.2.0" + } + }, + "@tauri-apps/cli-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-f3LR2RvTU2ulxYdK9Nc3vKaSpDChu52pz0BMWNrSs3dxs4WTVioie98Ufz+GorifkUp3sYXcJte3HzX6wH/QxQ==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.0.tgz", + "integrity": "sha512-m07QZaAZCtyobrjddfz/Rxf9GGutnBOpRMbNqVqCk0qKRJzHG1fIsLqkgZh6+qPv0zHpu7xi/FPcqTec72Cp8w==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-Id9eF1JtthZRFVtXAAVtSlI3uMT8cJ7LYmCSIl3mAXEUeaPBxnUs1i9X6/J+2Ho3yLEuuOxJ7PaJd+4v8wnEeg==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-NtfPkkpeMPl+i/tB/Fc8ST2rKO2vV8int/RkOvNGLCkhWcl4sbzKBol7tc4q8c8h0X7FXDcF1l/EOuGsZUAA5Q==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-tz+mOOVsy/TMdq2WJVIJl/iwW3OCWCyD5Fls3fhyJ4XpLfjn4G+C+oU0awXD/0se0ko81aq4D+r8eDx6oBRi0A==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-FH/wU+OWZjRQvrq/oequScr72I84XgOuRuMEpt/GqGD341cBJ8ithpoyzuiKsvjS6K0qMyRFzy3eyhQ7gwX+4Q==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-nLg30aBT9fI83sjIqaGPN7twbtE5LJy2DbKzxIlw59F+GT8HBdiM/2mZdTLB3AQb52yVHuGB1TVtWDsl0JHqCA==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-win32-ia32-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.0.tgz", + "integrity": "sha512-eXtgIgY0fawgcOuUjH8Y6PxwPxbK87Zl9XmA7Q0m58T7pIz+gcbgvtH8Bb+liYHoRYItIhQxVm+ui7Y59rI7Cg==", + "dev": true, + "optional": true + }, + "@tauri-apps/cli-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-egyM66R05AIbkaUDptpHurFTIYp3VM4H5OrRd3O2b0oXf8SoiXiyrHbQsHVHHDYyytKmwkdNqjdy+Vev/Vq25Q==", + "dev": true, + "optional": true + }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "requires": { + "@types/unist": "*" + } + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "@types/offscreencanvas": { + "version": "2019.7.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", + "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/react": { + "version": "18.0.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.25.tgz", + "integrity": "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.8.tgz", + "integrity": "sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/three": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.146.0.tgz", + "integrity": "sha512-75AgysUrIvTCB054eQa2pDVFurfeFW8CrMQjpzjt3yHBfuuknoSvvsESd/3EhQxPrz9si3+P0wiDUVsWUlljfA==", + "requires": { + "@types/webxr": "*" + } + }, + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "@types/webxr": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.0.tgz", + "integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==" + }, + "@use-gesture/core": { + "version": "10.2.22", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.22.tgz", + "integrity": "sha512-Ek0JZFYfk+hicLmoG094gm3YOuDMBNckHb988e59YOZoAkETT8dQSzT+g3QkSHSiP1m5wFXAGPSgxvOuwvGKHQ==" + }, + "@use-gesture/react": { + "version": "10.2.22", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.22.tgz", + "integrity": "sha512-ECo7ig16SxBE06ENIURO1woKEB6TC8qY3a0rugJjQ2f1o0Tj28xS/eYNyJuqzQB5YT0q5IrF7ZFpbx1p/5ohYA==", + "requires": { + "@use-gesture/core": "10.2.22" + } + }, + "@vitejs/plugin-react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-2.2.0.tgz", + "integrity": "sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==", + "dev": true, + "requires": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-jsx": "^7.19.0", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-jsx-self": "^7.18.6", + "@babel/plugin-transform-react-jsx-source": "^7.19.6", + "magic-string": "^0.26.7", + "react-refresh": "^0.14.0" + } + }, + "@webgpu/glslang": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" + }, + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "bidi-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.2.tgz", + "integrity": "sha512-rzSy/k7WdX5zOyeHHCOixGXbCHkyogkxPKL2r8QtzHmVQDiWCXUWa18bLdMWT9CYMLOYTjWpTHawuev2ouYJVw==", + "requires": { + "require-from-string": "^2.0.2" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "dev": true + }, + "ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" + }, + "chevrotain": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.4.1.tgz", + "integrity": "sha512-1y4vnssauVmrrP5MBaJ6DZvsv3BpXLlKVNK5S52fTGQHqg09qxMDBAz0wZbb04Ovc1pBCA4obcCjOlRioIV+cA==", + "requires": { + "@chevrotain/cst-dts-gen": "10.4.1", + "@chevrotain/gast": "10.4.1", + "@chevrotain/types": "10.4.1", + "@chevrotain/utils": "10.4.1", + "lodash": "4.17.21", + "regexp-to-ast": "0.5.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "requires": { + "character-entities": "^2.0.0" + } + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, + "detect-gpu": { + "version": "4.0.48", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-4.0.48.tgz", + "integrity": "sha512-qrJTrCeYG/5aaMaqHlbTZu3cTZB/TZJ/ZbDDEb712FMe5irqjGwp2fyG4ag+y19f4QGKg55dQXf8IuKo+oCmRw==", + "requires": { + "webgl-constants": "^1.1.1" + } + }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" + }, + "draco3d": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.5.tgz", + "integrity": "sha512-JVuNV0EJzD3LBYhGyIXJLeBID/EVtmFO1ZNhAYflTgiMiAJlbhXQmRRda/azjc8MRVMHh0gqGhiqHUo5dIXM8Q==" + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, + "esbuild": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", + "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.15.13", + "@esbuild/linux-loong64": "0.15.13", + "esbuild-android-64": "0.15.13", + "esbuild-android-arm64": "0.15.13", + "esbuild-darwin-64": "0.15.13", + "esbuild-darwin-arm64": "0.15.13", + "esbuild-freebsd-64": "0.15.13", + "esbuild-freebsd-arm64": "0.15.13", + "esbuild-linux-32": "0.15.13", + "esbuild-linux-64": "0.15.13", + "esbuild-linux-arm": "0.15.13", + "esbuild-linux-arm64": "0.15.13", + "esbuild-linux-mips64le": "0.15.13", + "esbuild-linux-ppc64le": "0.15.13", + "esbuild-linux-riscv64": "0.15.13", + "esbuild-linux-s390x": "0.15.13", + "esbuild-netbsd-64": "0.15.13", + "esbuild-openbsd-64": "0.15.13", + "esbuild-sunos-64": "0.15.13", + "esbuild-windows-32": "0.15.13", + "esbuild-windows-64": "0.15.13", + "esbuild-windows-arm64": "0.15.13" + } + }, + "esbuild-android-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", + "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", + "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", + "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", + "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", + "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", + "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", + "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", + "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", + "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", + "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", + "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", + "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", + "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", + "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", + "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", + "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", + "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", + "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", + "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.13", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", + "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "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 + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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 + }, + "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 + }, + "glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==" + }, + "hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "hast-util-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", + "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==" + }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "its-fine": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.0.6.tgz", + "integrity": "sha512-VZJZPwVT2kxe5KQv+TxCjojfLiUIut8zXDNLTxcM7gJ/xQ/bSPk5M0neZ+j3myy45KKkltY1mm1jyJgx3Fxsdg==", + "requires": { + "@types/react-reconciler": "^0.28.0" + }, + "dependencies": { + "@types/react-reconciler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.0.tgz", + "integrity": "sha512-5cjk9ottZAj7eaTsqzPUIlrVbh3hBAO2YaEL1rkjHKB3xNAId7oU8GhzvAX+gfmlfoxTwJnBjPxEHyxkEA1Ffg==", + "requires": { + "@types/react": "*" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" + }, + "ktx-parse": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.4.5.tgz", + "integrity": "sha512-MK3FOody4TXbFf8Yqv7EBbySw7aPvEcPX++Ipt6Sox+/YMFvR5xaTyhfNSk1AEmMy+RYIw81ctN4IMxCB8OAlg==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.clamp": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lodash.clamp/-/lodash.clamp-4.0.3.tgz", + "integrity": "sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==" + }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, + "longest-streak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", + "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==" + }, + "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==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "magic-string": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", + "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "markdown-table": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", + "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==" + }, + "mdast-util-definitions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", + "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "mdast-util-find-and-replace": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.1.tgz", + "integrity": "sha512-SobxkQXFAdd4b5WmEakmkVoh18icjQRxGy5OWTCzgsLRm1Fu/KCtwD1HIQSsmq5ZRjVH0Ehwg6/Fn3xIUk+nKw==", + "requires": { + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" + } + } + }, + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-gfm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz", + "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==", + "requires": { + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + } + }, + "mdast-util-gfm-autolink-literal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz", + "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==", + "requires": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + } + }, + "mdast-util-gfm-footnote": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz", + "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" + } + }, + "mdast-util-gfm-strikethrough": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.2.tgz", + "integrity": "sha512-T/4DVHXcujH6jx1yqpcAYYwd+z5lAYMw4Ls6yhTfbMMtCt0PHY4gEfhW9+lKsLBtyhUGKRIzcUA2FATVqnvPDA==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-gfm-table": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", + "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", + "requires": { + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-gfm-task-list-item": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz", + "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-to-hast": { + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "mdast-util-to-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", + "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==" + }, + "meshline": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-2.0.4.tgz", + "integrity": "sha512-Jh6DJl/zLqA4xsKvGv5950jr2ukyXQE1wgxs8u94cImHrvL6soVIggqjP+2hVHZXGYaKnWszhtjuCbKNeQyYiw==", + "requires": {} + }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz", + "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==", + "requires": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-footnote": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz", + "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==", + "requires": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-strikethrough": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz", + "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-table": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz", + "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-tagfilter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz", + "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-gfm-task-list-item": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz", + "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "requires": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==" + }, + "micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==" + }, + "micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==" + }, + "micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==" + }, + "mmd-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "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==" + }, + "opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", + "requires": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + } + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss": { + "version": "8.4.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", + "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "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==" + } + } + }, + "property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==" + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-composer": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", + "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", + "requires": { + "prop-types": "^15.6.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "react-markdown": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", + "integrity": "sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==", + "requires": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + } + }, + "react-merge-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", + "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==" + }, + "react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "dependencies": { + "scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "requires": { + "loose-envify": "^1.1.0" + } + } + } + }, + "react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true + }, + "react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "requires": { + "debounce": "^1.2.1" + } + }, + "recoil": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.6.tgz", + "integrity": "sha512-hsBEw7jFdpBCY/tu2GweiyaqHKxVj6EqF2/SfrglbKvJHhpN57SANWvPW+gE90i3Awi+A5gssOd3u+vWlT+g7g==", + "requires": { + "hamt_plus": "1.0.2" + } + }, + "regenerator-runtime": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + }, + "regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" + }, + "remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + } + }, + "remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, + "remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + } + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "requires": { + "mri": "^1.1.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==" + }, + "string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + }, + "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 + }, + "suspend-react": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.0.8.tgz", + "integrity": "sha512-ZC3r8Hu1y0dIThzsGw0RLZplnX9yXwfItcvaIzJc2VQVi8TGyGDlu92syMB5ulybfvGLHAI5Ghzlk23UBPF8xg==", + "requires": {} + }, + "three": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.146.0.tgz", + "integrity": "sha512-1lvNfLezN6OJ9NaFAhfX4sm5e9YCzHtaRgZ1+B4C+Hv6TibRMsuBAM5/wVKzxjpYIlMymvgsHEFrrigEfXnb2A==" + }, + "three-mesh-bvh": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.5.18.tgz", + "integrity": "sha512-lJQkt4A+pfHMf8Pbyqm5UiIBoVtp3cuy5rrTpuhIaJlbAobJW3/uQxJVZKiHaGi1Bs+5Svb+T8xIS17EqjG2ZA==", + "requires": {} + }, + "three-stdlib": { + "version": "2.17.4", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.17.4.tgz", + "integrity": "sha512-Xh9+B/1RL0YXRjWgLilbK/5qL7hVOWMF5sQ1seKqGvR4svNvQPU+vCZkL2sUaZ0usc/C3FpyGTuwbqo+eW444Q==", + "requires": { + "@babel/runtime": "^7.16.7", + "@types/offscreencanvas": "^2019.6.4", + "@webgpu/glslang": "^0.0.15", + "chevrotain": "^10.1.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "ktx-parse": "^0.4.5", + "mmd-parser": "^1.0.4", + "opentype.js": "^1.3.3", + "potpack": "^1.0.1", + "zstddec": "^0.0.2" + } + }, + "tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "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 + }, + "trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" + }, + "troika-three-text": { + "version": "0.46.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.46.4.tgz", + "integrity": "sha512-Qsv0HhUKTZgSmAJs5wvO7YlBoJSP9TGPLmrg+K9pbQq4lseQdcevbno/WI38bwJBZ/qS56hvfqEzY0zUEFzDIw==", + "requires": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.46.0", + "troika-worker-utils": "^0.46.0", + "webgl-sdf-generator": "1.1.1" + } + }, + "troika-three-utils": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.46.0.tgz", + "integrity": "sha512-llHyrXAcwzr0bpg80GxsIp73N7FuImm4WCrKDJkAqcAsWmE5pfP9+Qzw+oMWK1P/AdHQ79eOrOl9NjyW4aOw0w==", + "requires": {} + }, + "troika-worker-utils": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.46.0.tgz", + "integrity": "sha512-bzOx5f2ZBxkFhXtIvDJlLn2AI3bzCkGVbCndl/2dL5QZrwHEKl45OEIilCxYQQWJG1rEbOD9O80tMjoYjw19OA==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + } + }, + "unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==" + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==" + }, + "unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, + "uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + } + }, + "vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + } + }, + "vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + } + }, + "vite": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.3.tgz", + "integrity": "sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==", + "dev": true, + "requires": { + "esbuild": "^0.15.9", + "fsevents": "~2.3.2", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + } + }, + "webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" + }, + "zstddec": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" + }, + "zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "requires": {} + }, + "zwitch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.3.tgz", + "integrity": "sha512-dn/sDAIuRCsXGnBD4P+SA6nv7Y54HQZjC4SPL8PToU3714zu7wSEc1129D/i0+vvjRfOlFo4Zqrpwj+Zhcykhw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..aeb13580 --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "pocket-sync", + "private": true, + "version": "2.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "tauri": "tauri" + }, + "dependencies": { + "@react-three/drei": "^9.40.0", + "@react-three/fiber": "^8.9.1", + "@tauri-apps/api": "^1.1.0", + "@types/three": "^0.146.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-markdown": "^8.0.3", + "recoil": "^0.7.6", + "remark-gfm": "^3.0.1", + "three": "^0.146.0" + }, + "devDependencies": { + "@tauri-apps/cli": "^1.1.0", + "@types/node": "^18.7.10", + "@types/react": "^18.0.15", + "@types/react-dom": "^18.0.6", + "@vitejs/plugin-react": "^2.0.0", + "postcss-nesting": "^10.2.0", + "typescript": "^4.6.4", + "vite": "^3.0.2" + }, + "prettier": { + "trailingComma": "es5", + "tabWidth": 2, + "semi": false, + "singleQuote": false + } +} diff --git a/public/tauri.svg b/public/tauri.svg new file mode 100644 index 00000000..31b62c92 --- /dev/null +++ b/public/tauri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/readme_images/cores_list.png b/readme_images/cores_list.png new file mode 100644 index 00000000..c5de7f65 Binary files /dev/null and b/readme_images/cores_list.png differ diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100644 index 00000000..f4dfb82b --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,4 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100644 index 00000000..1c49b1fc --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,4181 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "atk" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +dependencies = [ + "atk-sys", + "bitflags", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "attohttpc" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" +dependencies = [ + "flate2", + "http", + "log", + "native-tls", + "serde", + "serde_json", + "serde_urlencoded", + "url", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cairo-rs" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "cargo_toml" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa0e3586af56b3bfa51fca452bd56e8dbbbd5d8d81cbf0b7e4e35b695b537eb8" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f89d248799e3f15f91b70917f65381062a01bb8e222700ea0e5a7ff9785f9c" +dependencies = [ + "byteorder", + "uuid 0.8.2", +] + +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-expr" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" +dependencies = [ + "cfg-if", +] + +[[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 = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "dbus" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8bcdd56d2e5c4ed26a529c5a9029f5db8290d433497506f958eae3be148eb6" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "deflate" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "dtoa-short" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "field-offset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" +dependencies = [ + "memoffset", + "rustc_version 0.3.3", +] + +[[package]] +name = "filetime" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.42.0", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide 0.5.4", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-locks" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb42d4fb72227be5778429f9ef5240a38a358925a49f05b5cf702ce7c7e558a" +dependencies = [ + "futures-channel", + "futures-task", + "tokio", +] + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps 6.0.3", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps 6.0.3", + "x11", +] + +[[package]] +name = "generator" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc184cace1cea8335047a471cc1da80f18acf8a76f3bab2028d499e328948ec7" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.32.0", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gio" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.3", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" +dependencies = [ + "anyhow", + "heck 0.4.0", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "globset" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "gtk" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +dependencies = [ + "atk", + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps 6.0.3", +] + +[[package]] +name = "gtk3-macros" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "html5ever" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.4", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.4", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "ico" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a4b3331534254a9b64095ae60d3dc2a8225a7a70229cd5888be127cdc1f6804" +dependencies = [ + "byteorder", + "png 0.11.0", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "infer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b2b533137b9cad970793453d4f921c2e91312a6d88b1085c07bc15fc51bb3b" +dependencies = [ + "cfb", +] + +[[package]] +name = "inflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f9f47468e9a76a6452271efadc88fe865a82be91fe75e6c0c57b87ccea59d4" +dependencies = [ + "adler32", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "javascriptcore-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +dependencies = [ + "bitflags", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f995a3c8f2bc3dd52a18a583e90f9ec109c047fa1603a853e46bcda14d2e279d" +dependencies = [ + "serde", + "serde_json", + "treediff", +] + +[[package]] +name = "kuchiki" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358" +dependencies = [ + "cssparser", + "html5ever", + "matches", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libdbus-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "mac-notification-sys" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e72d50edb17756489e79d52eb146927bec8eba9dd48faadf9ef08bca3791ad5" +dependencies = [ + "cc", + "dirs-next", + "objc-foundation", + "objc_id", + "time", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" +dependencies = [ + "log", + "phf 0.8.0", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.42.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "notify-rust" +version = "4.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368e89ea58df747ce88be669ae44e79783c1d30bfd540ad0fc520b3f41f0b3b0" +dependencies = [ + "dbus", + "mac-notification-sys", + "tauri-winrt-notification", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "open" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a3100141f1733ea40b53381b0ae3117330735ef22309a190ac57b9576ea716" +dependencies = [ + "pathdiff", + "windows-sys 0.36.1", +] + +[[package]] +name = "openssl" +version = "0.10.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_info" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "os_pipe" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dceb7e43f59c35ee1548045b2c72945a5a3bb6ce6d6f07cdc13dc8f6bc4930a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.0.3", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "plist" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225" +dependencies = [ + "base64", + "indexmap", + "line-wrap", + "serde", + "time", + "xml-rs", +] + +[[package]] +name = "png" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925" +dependencies = [ + "bitflags", + "deflate", + "inflate", + "num-iter", +] + +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide 0.6.2", +] + +[[package]] +name = "pocket-sync" +version = "0.0.0" +dependencies = [ + "bytes", + "futures", + "futures-locks", + "reqwest", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tempdir", + "time", + "tokio", + "walkdir", + "zip", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.8", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rfd" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" +dependencies = [ + "block", + "dispatch", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "lazy_static", + "log", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.37.0", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.14", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys 0.36.1", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +dependencies = [ + "itoa 1.0.4", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.4", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shared_child" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soup2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +dependencies = [ + "bitflags", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +dependencies = [ + "loom", +] + +[[package]] +name = "string_cache" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" +dependencies = [ + "cfg-expr 0.11.0", + "heck 0.4.0", + "pkg-config", + "toml", + "version-compare 0.1.1", +] + +[[package]] +name = "tao" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42c460173627564bde252ca5ebf346ba5b37c5cee1a445782bacc8e9b8d38b5e" +dependencies = [ + "bitflags", + "cairo-rs", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdk", + "gdk-pixbuf", + "gdk-sys", + "gdkx11-sys", + "gio", + "glib", + "glib-sys", + "gtk", + "image", + "instant", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "paste", + "png 0.17.7", + "raw-window-handle", + "scopeguard", + "serde", + "unicode-segmentation", + "uuid 1.2.1", + "windows 0.39.0", + "windows-implement", + "x11-dl", +] + +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tauri" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac135e45c2923bd91edbb95a0d656f8d025389697e34d6d79166952bfa79c61c" +dependencies = [ + "anyhow", + "attohttpc", + "cocoa", + "dirs-next", + "embed_plist", + "encoding_rs", + "flate2", + "futures-util", + "glib", + "glob", + "gtk", + "heck 0.4.0", + "http", + "ignore", + "notify-rust", + "objc", + "once_cell", + "open", + "os_info", + "os_pipe", + "percent-encoding", + "rand 0.8.5", + "raw-window-handle", + "regex", + "rfd", + "semver 1.0.14", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "shared_child", + "state", + "tar", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "tempfile", + "thiserror", + "tokio", + "url", + "uuid 1.2.1", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-build" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef796f49abc98e6de0abe1b655120addc9d82363d8fc2304e71a4177c25e783c" +dependencies = [ + "anyhow", + "cargo_toml", + "heck 0.4.0", + "json-patch", + "semver 1.0.14", + "serde_json", + "tauri-utils", + "winres", +] + +[[package]] +name = "tauri-codegen" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb77cf7bfe3d8f886e73a7fa6157587d015c599671180b76595c1aef175ba8" +dependencies = [ + "base64", + "brotli", + "ico", + "json-patch", + "plist", + "png 0.17.7", + "proc-macro2", + "quote", + "regex", + "semver 1.0.14", + "serde", + "serde_json", + "sha2", + "tauri-utils", + "thiserror", + "time", + "uuid 1.2.1", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f24f481b0b2acfc288ac78755f00ebea53992c7365a165af64cb5ae00806edea" +dependencies = [ + "heck 0.4.0", + "proc-macro2", + "quote", + "syn", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-runtime" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc5d54c476defa5436e70e0d0a06e3cb0f49b6f863895995d5e3769411769cf" +dependencies = [ + "gtk", + "http", + "http-range", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror", + "uuid 1.2.1", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-runtime-wry" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c55091701426c2519c7e9f1dc2dd33e533af4e75eae89cedc6995409351a2" +dependencies = [ + "cocoa", + "gtk", + "percent-encoding", + "rand 0.8.5", + "raw-window-handle", + "tauri-runtime", + "tauri-utils", + "uuid 1.2.1", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64c9a09ba1538b8e67ae8c78c10904f36ce38d364bf7f089ec807032a826b02" +dependencies = [ + "brotli", + "ctor", + "glob", + "heck 0.4.0", + "html5ever", + "infer", + "json-patch", + "kuchiki", + "memchr", + "phf 0.10.1", + "proc-macro2", + "quote", + "semver 1.0.14", + "serde", + "serde_json", + "serde_with", + "thiserror", + "url", + "walkdir", + "windows 0.39.0", +] + +[[package]] +name = "tauri-winrt-notification" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58de036c4d2e20717024de2a3c4bf56c301f07b21bc8ef9b57189fce06f1f3b" +dependencies = [ + "quick-xml", + "strum", + "windows 0.39.0", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa 1.0.4", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "treediff" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff" +dependencies = [ + "serde_json", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "uuid" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[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.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup2", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +dependencies = [ + "atk-sys", + "bitflags", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pango-sys", + "pkg-config", + "soup2-sys", + "system-deps 6.0.3", +] + +[[package]] +name = "webview2-com" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "webview2-com-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "webview2-com-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror", + "windows 0.39.0", + "windows-bindgen", + "windows-metadata", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbedf6db9096bc2364adce0ae0aa636dcd89f3c3f2cd67947062aaf0ca2a10ec" +dependencies = [ + "windows_aarch64_msvc 0.32.0", + "windows_i686_gnu 0.32.0", + "windows_i686_msvc 0.32.0", + "windows_x86_64_gnu 0.32.0", + "windows_x86_64_msvc 0.32.0", +] + +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows-implement", + "windows_aarch64_msvc 0.39.0", + "windows_i686_gnu 0.39.0", + "windows_i686_msvc 0.39.0", + "windows_x86_64_gnu 0.39.0", + "windows_x86_64_msvc 0.39.0", +] + +[[package]] +name = "windows-bindgen" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +dependencies = [ + "windows-metadata", + "windows-tokens", +] + +[[package]] +name = "windows-implement" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +dependencies = [ + "syn", + "windows-tokens", +] + +[[package]] +name = "windows-metadata" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows-tokens" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + +[[package]] +name = "wry" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d297b203eae65b095af16c02978b7932be1968012b4da7138390edf34dea5" +dependencies = [ + "base64", + "block", + "cocoa", + "core-graphics", + "crossbeam-channel", + "dunce", + "gdk", + "gio", + "glib", + "gtk", + "html5ever", + "http", + "kuchiki", + "libc", + "log", + "objc", + "objc_id", + "once_cell", + "serde", + "serde_json", + "sha2", + "soup2", + "tao", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "x11" +version = "2.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7ae97874a928d821b061fce3d1fc52f08071dd53c89a6102bc06efcac3b2908" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "zip" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.1+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +dependencies = [ + "cc", + "libc", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 00000000..3826f31d --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "pocket-sync" +version = "0.0.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.57" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +tauri-build = { version = "1.1", features = [] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { version = "1.1", features = ["api-all"] } +zip = { version = "0.6.3", feature = ["deflate", "time"] } +reqwest = "0.11.12" +futures = "0.3.25" +futures-locks = "0.7.0" +tokio = "1.21.2" +tempdir = "0.3.7" +walkdir = "2.3.2" +bytes = "1.2.1" +time = "0.3.17" + +[features] +# by default Tauri runs in production mode +# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL +default = [ "custom-protocol" ] +# this feature is used used for production builds where `devPath` points to the filesystem +# DO NOT remove this +custom-protocol = [ "tauri/custom-protocol" ] diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 00000000..795b9b7c --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 00000000..1c123957 Binary files /dev/null and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 00000000..7db2924a Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 00000000..b2ea7060 Binary files /dev/null and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 00000000..812ee8f2 Binary files /dev/null and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 00000000..7142207a Binary files /dev/null and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 00000000..b9d6fe11 Binary files /dev/null and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 00000000..680cc3ce Binary files /dev/null and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 00000000..58b8b656 Binary files /dev/null and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 00000000..a1f2864f Binary files /dev/null and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 00000000..5e3a88c7 Binary files /dev/null and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 00000000..969aa7ad Binary files /dev/null and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 00000000..218f9c4f Binary files /dev/null and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 00000000..6e1d3cdc Binary files /dev/null and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 00000000..b662b1fc Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 00000000..7f248d78 Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 00000000..c41ab689 Binary files /dev/null and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/src/checks.rs b/src-tauri/src/checks.rs new file mode 100644 index 00000000..0990876b --- /dev/null +++ b/src-tauri/src/checks.rs @@ -0,0 +1,69 @@ +use std::{ + path::PathBuf, + thread::{self, sleep}, + time::Duration, +}; + +use serde::{Deserialize, Serialize}; +use tauri::{App, Manager}; + +use crate::PocketSyncState; + +pub fn check_if_folder_looks_like_pocket(path: &PathBuf) -> bool { + let json_path = path.join("Analogue_Pocket.json"); + + if !json_path.exists() { + return false; + } + + let assets_path = path.join("Assets"); + + if !assets_path.exists() { + return false; + } + + let cores_path = path.join("Cores"); + + if !cores_path.exists() { + return false; + } + + // yeah, looks enough like a Pocket + return true; +} + +pub fn start_connection_thread(app: &App) -> Result<(), Box<(dyn std::error::Error + 'static)>> { + let app_handle = app.handle(); + + thread::spawn(move || { + let main_window = app_handle.get_window("main").unwrap(); + let mut was_connected: bool = false; + loop { + tauri::async_runtime::block_on(async { + let state: tauri::State = tauri::Manager::state(&app_handle); + let pocket_path = state.0.read().await; + // println!("checking if still connected {}", pocket_path.exists()); + if !pocket_path.exists() && was_connected { + was_connected = false; + main_window + .emit( + "pocket-connection", + ConnectionEventPayload { connected: false }, + ) + .unwrap(); + } else if pocket_path.exists() && !was_connected { + was_connected = true; + } + }); + + sleep(Duration::from_secs(5)); + } + }); + + Ok(()) +} + +#[derive(Serialize, Deserialize, Clone)] +struct ConnectionEventPayload { + connected: bool, +} diff --git a/src-tauri/src/install_zip.rs b/src-tauri/src/install_zip.rs new file mode 100644 index 00000000..4eb26e20 --- /dev/null +++ b/src-tauri/src/install_zip.rs @@ -0,0 +1,258 @@ +use reqwest::StatusCode; +use serde::{Deserialize, Serialize}; +use std::{fs, io::Cursor, path::PathBuf, thread}; +use tauri::{App, Manager, Window}; +use tempdir::TempDir; +use zip::ZipArchive; + +use crate::PocketSyncState; + +#[derive(Serialize, Deserialize)] +struct InstallInfo { + core_name: String, + zip_url: String, +} + +#[derive(Serialize, Deserialize, Clone)] +struct PathStatus { + path: String, + exists: bool, +} + +#[derive(Serialize, Deserialize, Clone)] +struct InstallConfirmation { + paths: Vec, + allow: bool, +} + +#[derive(Serialize, Deserialize, Clone)] +struct InstallZipEventPayload { + title: String, + files: Option>, + progress: Option, +} + +#[derive(Serialize, Deserialize, Clone)] +struct ZipInstallFinishedPayload { + error: Option, +} + +#[derive(Serialize, Deserialize, Clone)] +struct ZipInstallProgress { + max: usize, + value: usize, +} + +struct Titles { + title: String, + installing_title: String, +} + +pub fn start_zip_thread(app: &App) -> Result<(), Box<(dyn std::error::Error + 'static)>> { + let app_handle = app.handle(); + let app_handle_b = app.handle(); + + thread::spawn(move || { + let main_window = app_handle.get_window("main").unwrap(); + let main_window_b = app_handle.get_window("main").unwrap(); + let main_window_c = app_handle.get_window("main").unwrap(); + + main_window.on_window_event(move |event| { + if let tauri::WindowEvent::FileDrop(e) = event { + if let tauri::FileDropEvent::Dropped(paths) = e { + tokio::task::block_in_place(|| { + tauri::async_runtime::block_on(async { + let state: tauri::State = app_handle_b.state(); + let pocket_path = state.0.read().await; + + if !pocket_path.exists() || paths.len() != 1 { + return; + } + + for path in paths { + if !path + .file_name() + .and_then(|f| f.to_str()) + .unwrap() + .ends_with(".zip") + { + continue; + } + let zip_file = fs::read(path).unwrap(); + let cursor = Cursor::new(zip_file); + let archive = zip::ZipArchive::new(cursor).unwrap(); + + start_zip_install_flow( + archive, + Titles { + title: String::from("Install Zip"), + installing_title: (String::from("Installing Zip...")), + }, + pocket_path.clone(), + &main_window_c, + ) + .await + .unwrap(); + } + }) + }); + } + } + }); + + main_window.listen("install-core", move |event| { + emit_progress("Install Core", None, None, &main_window_b); + + tokio::task::block_in_place(|| { + tauri::async_runtime::block_on(async { + let state: tauri::State = app_handle.state(); + let pocket_path = state.0.read().await; + + let install: InstallInfo = + serde_json::from_str(event.payload().unwrap()).unwrap(); + let response = reqwest::get(install.zip_url).await.unwrap(); + + // dbg!(&response); + + match response.status() { + StatusCode::OK => { + let zip_file = response.bytes().await.unwrap(); + let cursor = Cursor::new(zip_file); + let archive = zip::ZipArchive::new(cursor).unwrap(); + + start_zip_install_flow( + archive, + Titles { + title: String::from("Install Core"), + installing_title: (String::from("Installing Core...")), + }, + pocket_path.clone(), + &main_window_b, + ) + .await + .unwrap(); + } + _s => { + emit_finished( + Some(String::from("Unable to download ZIP")), + &main_window_b, + ); + } + } + }); + }) + }) + }); + + Ok(()) +} + +fn emit_progress( + title: &str, + files: Option>, + progress: Option, + window: &Window, +) -> () { + window + .emit( + "install-zip-event", + InstallZipEventPayload { + title: String::from(title), + files: files, + progress, + }, + ) + .unwrap(); +} + +fn emit_finished(error: Option, window: &Window) -> () { + window + .emit("install-zip-finished", ZipInstallFinishedPayload { error }) + .unwrap(); +} + +async fn start_zip_install_flow( + mut archive: ZipArchive, + titles: Titles, + pocket_path: PathBuf, + window: &Window, +) -> Result<(), ()> { + emit_progress( + &titles.title, + Some(get_file_names(&archive, &pocket_path)), + None, + &window, + ); + + let main_window_c = window.clone(); + + window.once("install-confirmation", move |event| { + let install_confirm: InstallConfirmation = + serde_json::from_str(event.payload().unwrap()).unwrap(); + + if !install_confirm.allow { + emit_finished(None, &main_window_c); + return (); + } + + emit_progress( + &titles.installing_title, + None, + Some(ZipInstallProgress { + value: 0, + max: install_confirm.paths.len(), + }), + &main_window_c, + ); + + let tmp_dir = TempDir::new("zip_install_tmp").unwrap(); + let tmp_path = tmp_dir.into_path(); + archive.extract(&tmp_path).unwrap(); + + for (index, path) in install_confirm.paths.iter().enumerate() { + let destination = pocket_path.join(&path); + let source = tmp_path.join(&path); + + if destination.is_dir() && destination.exists() { + continue; + } + + // println!("copy from {:?} to {:?}", &source, &destination); + + fs::create_dir_all(destination.parent().unwrap()).unwrap(); + if !source.is_dir() { + fs::copy(&source, &destination).unwrap(); + } + + emit_progress( + &titles.installing_title, + None, + Some(ZipInstallProgress { + value: index + 1, + max: install_confirm.paths.len(), + }), + &main_window_c, + ); + } + emit_finished(None, &main_window_c); + }); + + Ok(()) +} + +fn get_file_names( + zip: &ZipArchive, + pocket_path: &PathBuf, +) -> Vec { + let files = zip.file_names(); + files + .into_iter() + .map(|f| { + let path = pocket_path.join(f); + PathStatus { + exists: path.exists(), + path: String::from(f), + } + }) + .collect() +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 00000000..ad478aef --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,346 @@ +#![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" +)] + +use checks::{check_if_folder_looks_like_pocket, start_connection_thread}; +use futures_locks::RwLock; +use install_zip::start_zip_thread; +use saves_zip::{ + build_save_zip, read_save_zip_list, read_saves_in_zip, restore_save_from_zip, SaveZipFile, +}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::fs::{self}; +use std::io::Read; +use std::io::Write; +use std::path::PathBuf; +use tauri::api::dialog; +use tauri::{App, Window}; +use walkdir::{DirEntry, WalkDir}; +mod checks; +mod install_zip; +mod saves_zip; +struct PocketSyncState(RwLock); + +// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command +#[tauri::command(async)] +async fn open_pocket(state: tauri::State<'_, PocketSyncState>) -> Result, ()> { + if let Some(pocket_path) = dialog::blocking::FileDialogBuilder::new().pick_folder() { + if !check_if_folder_looks_like_pocket(&pocket_path) { + return Ok(None); + } + + let mut path_state = state.0.write().await; + *path_state = pocket_path; + + Ok(Some(String::from(path_state.to_str().unwrap()))) + } else { + Err(()) + } +} + +#[tauri::command(async)] +async fn read_binary_file( + state: tauri::State<'_, PocketSyncState>, + path: &str, +) -> Result, ()> { + let pocket_path = state.0.read().await; + let path = pocket_path.join(path); + + let mut f = fs::File::open(&path).expect(&format!("no file found: {:?}", path)); + let metadata = fs::metadata(&path).expect("unable to read metadata"); + let mut buffer = vec![0; metadata.len() as usize]; + + f.read(&mut buffer).expect("buffer overflow"); + + Ok(buffer) +} + +#[tauri::command(async)] +async fn read_text_file( + state: tauri::State<'_, PocketSyncState>, + path: &str, +) -> Result { + let pocket_path = state.0.read().await; + let path = pocket_path.join(path); + // println!("reading text file: {:?}", &path); + let video_json = fs::read_to_string(path).unwrap(); + Ok(video_json) +} + +#[tauri::command(async)] +async fn file_exists(state: tauri::State<'_, PocketSyncState>, path: &str) -> Result { + let pocket_path = state.0.read().await; + let path = pocket_path.join(path); + // println!("checking if file exists @{:?}", &path); + Ok(path.exists()) +} + +#[tauri::command(async)] +fn save_file(path: &str, buffer: Vec) -> Result { + let file_path = PathBuf::from(path); + // println!("Saving file {:?}", &file_path); + let mut file = fs::File::create(file_path).unwrap(); + file.write_all(&buffer).unwrap(); + Ok(true) +} + +#[tauri::command(async)] +async fn list_files( + path: &str, + state: tauri::State<'_, PocketSyncState>, +) -> Result, ()> { + let pocket_path = state.0.read().await; + let dir_path = pocket_path.join(path); + + if !dir_path.exists() { + return Ok(vec![]); + } + + let paths = fs::read_dir(dir_path).unwrap(); + + Ok(paths + .into_iter() + .filter(Result::is_ok) + .map(|p| p.unwrap()) + .map(|p| p.file_name().into_string().unwrap()) + .filter(|s| !s.starts_with(".")) + .collect()) +} + +#[tauri::command(async)] +async fn walkdir_list_files( + path: &str, + extensions: Vec<&str>, + state: tauri::State<'_, PocketSyncState>, +) -> Result, ()> { + let pocket_path = state.0.read().await; + let dir_path = pocket_path.join(path); + + if !dir_path.exists() { + return Ok(vec![]); + } + + fn is_hidden(entry: &DirEntry) -> bool { + entry + .file_name() + .to_str() + .map(|s| s.starts_with(".")) + .unwrap_or(false) + } + + let walker = WalkDir::new(&dir_path).into_iter(); + let dir_path_str = &dir_path.to_str().unwrap(); + Ok(walker + .filter_entry(|e| !is_hidden(e)) + .into_iter() + .filter_map(|x| x.ok()) + .map(|e| String::from(e.path().to_str().unwrap())) + .filter(|s| extensions.iter().any(|e| s.ends_with(e))) + .map(|s| s.replace(dir_path_str, "")) + .collect()) +} + +#[tauri::command(async)] +async fn uninstall_core( + core_name: &str, + state: tauri::State<'_, PocketSyncState>, +) -> Result { + let pocket_path = state.0.write().await; + let core_path = pocket_path.join("Cores").join(core_name); + // println!("I will remove {:?}", &core_path); + if core_path.exists() && core_path.is_dir() { + // not sure why this doesn't work + // fs::remove_dir_all(core_path).unwrap(); + + if let Ok(entries) = std::fs::read_dir(&core_path) { + for entry in entries { + let path = entry.unwrap().path(); + // println!("{:?}", path); + + if path.exists() { + std::fs::remove_file(path).unwrap(); + } + } + }; + + fs::remove_dir(&core_path).unwrap(); + } else { + println!("Weird, it's gone already"); + } + + Ok(true) +} + +#[tauri::command(async)] +async fn install_archive_files( + files: Vec, + archive_url: &str, + state: tauri::State<'_, PocketSyncState>, + window: Window, +) -> Result { + // println!("installing archive files"); + let pocket_path = state.0.read().await; + let file_count = files.len(); + + let mut failed_already = HashSet::new(); + + window + .emit( + "file-progress", + FileProgressPayload { + value: 0, + max: file_count, + }, + ) + .unwrap(); + + for (index, file) in files.into_iter().enumerate() { + let full_url = format!("{}/{}", archive_url, file.filename); + + // println!("Downloading from {full_url}"); + + if !failed_already.contains(&file.filename) { + let response = reqwest::get(&full_url).await; + + match response { + Err(e) => { + println!("Error downloading from {full_url}: ({e})"); + failed_already.insert(file.filename); + } + Ok(r) => { + if r.status() != 200 { + println!("Unable to find {full_url}, skipping"); + failed_already.insert(file.filename); + } else { + let folder = pocket_path.join(file.path); + + if !folder.exists() { + fs::create_dir_all(&folder).unwrap(); + } + + let new_file_path = folder.join(file.filename); + let mut dest = fs::File::create(&new_file_path).unwrap(); + let content = r.bytes().await.unwrap(); + let mut content_cusror = std::io::Cursor::new(content); + std::io::copy(&mut content_cusror, &mut dest).unwrap(); + } + } + } + } + + window + .emit( + "file-progress", + FileProgressPayload { + value: index + 1, + max: file_count, + }, + ) + .unwrap(); + } + + Ok(true) +} + +#[tauri::command(async)] +async fn backup_saves( + save_paths: Vec<&str>, + zip_path: &str, + max_count: usize, + state: tauri::State<'_, PocketSyncState>, +) -> Result { + let pocket_path = state.0.read().await; + build_save_zip(&pocket_path, save_paths, zip_path, max_count).unwrap(); + + Ok(true) +} + +#[tauri::command(async)] +async fn list_backup_saves(backup_path: &str) -> Result { + let path = PathBuf::from(backup_path); + if !path.exists() { + return Ok(BackupSavesResponse { + files: vec![], + exists: false, + }); + } + + let files = read_save_zip_list(&path).unwrap(); + + Ok(BackupSavesResponse { + files, + exists: true, + }) +} + +#[tauri::command(async)] +async fn list_saves_in_zip(zip_path: &str) -> Result, ()> { + let path = PathBuf::from(zip_path); + if !path.exists() { + return Ok(vec![]); + } + + read_saves_in_zip(&path) +} + +#[tauri::command(async)] +async fn restore_save( + zip_path: &str, + file_path: &str, + state: tauri::State<'_, PocketSyncState>, +) -> Result<(), ()> { + let pocket_path = state.0.read().await; + let path = PathBuf::from(zip_path); + restore_save_from_zip(&path, file_path, &pocket_path); + + Ok(()) +} + +fn main() { + tauri::Builder::default() + .manage(PocketSyncState(Default::default())) + .invoke_handler(tauri::generate_handler![ + open_pocket, + list_files, + walkdir_list_files, + read_binary_file, + read_text_file, + save_file, + uninstall_core, + install_archive_files, + file_exists, + backup_saves, + list_backup_saves, + list_saves_in_zip, + restore_save + ]) + .setup(|app| start_threads(&app)) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} + +fn start_threads(app: &App) -> Result<(), Box<(dyn std::error::Error + 'static)>> { + start_connection_thread(&app).unwrap(); + start_zip_thread(&app).unwrap(); + Ok(()) +} + +#[derive(Serialize, Deserialize)] +struct DownloadFile { + filename: String, + path: String, +} + +#[derive(Serialize, Deserialize, Clone)] +struct FileProgressPayload { + value: usize, + max: usize, +} + +#[derive(Serialize, Deserialize)] +struct BackupSavesResponse { + files: Vec, + exists: bool, +} diff --git a/src-tauri/src/saves_zip.rs b/src-tauri/src/saves_zip.rs new file mode 100644 index 00000000..ff790e57 --- /dev/null +++ b/src-tauri/src/saves_zip.rs @@ -0,0 +1,168 @@ +use serde::{Deserialize, Serialize}; +use std::{ + cmp::{Ord, Ordering}, + fs::{self, File}, + io::{Cursor, Read, Write}, + path::{Path, PathBuf}, + time::SystemTime, +}; +use tempdir::TempDir; +use walkdir::WalkDir; +use zip::{write::FileOptions, DateTime}; + +#[derive(Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct SaveZipFile { + last_modified: u32, + filename: String, +} + +impl Ord for SaveZipFile { + fn cmp(&self, other: &Self) -> Ordering { + self.last_modified.cmp(&other.last_modified) + } +} + +static FILE_PREFIX: &str = "pocket-sync-save-backup__"; + +pub fn restore_save_from_zip(zip_path: &PathBuf, file_path: &str, pocket_path: &PathBuf) -> () { + let zip_file = fs::read(zip_path).unwrap(); + let cursor = Cursor::new(zip_file); + let mut archive = zip::ZipArchive::new(cursor).unwrap(); + + let tmp_dir = TempDir::new("zip_saves_tmp").unwrap(); + let tmp_path = tmp_dir.into_path(); + archive.extract(&tmp_path).unwrap(); + + let src_file_path = tmp_path.join(remove_leading_slash(file_path)); + let dest_file_path = pocket_path + .join("Saves") + .join(remove_leading_slash(file_path)); + + // println!("from {:?} to {:?}", src_file_path, dest_file_path); + + fs::create_dir_all(dest_file_path.parent().unwrap()).unwrap(); + fs::copy(&src_file_path, &dest_file_path).unwrap(); +} + +pub fn read_saves_in_zip(zip_path: &PathBuf) -> Result, ()> { + let zip_file = fs::read(zip_path).unwrap(); + let cursor = Cursor::new(zip_file); + let mut archive = zip::ZipArchive::new(cursor).unwrap(); + + let tmp_dir = TempDir::new("zip_saves_tmp").unwrap(); + let tmp_path = tmp_dir.into_path(); + archive.extract(&tmp_path).unwrap(); + + let walker = WalkDir::new(&tmp_path).into_iter(); + let dir_path_str = &tmp_path.to_str().unwrap(); + Ok(walker + .into_iter() + .filter_map(|x| x.ok()) + .map(|e| { + let file_path = e.path(); + let metadata = file_path.metadata().unwrap(); + let last_modified = time::OffsetDateTime::from(metadata.created().unwrap()); + + SaveZipFile { + filename: String::from(e.path().to_str().unwrap()).replace(dir_path_str, ""), + last_modified: last_modified.unix_timestamp().try_into().unwrap(), + } + }) + .collect()) +} + +pub fn read_save_zip_list(dir_path: &PathBuf) -> Result, ()> { + if !dir_path.exists() { + return Ok(vec![]); + } + let paths = fs::read_dir(dir_path).unwrap(); + Ok(paths + .into_iter() + .filter(Result::is_ok) + .map(|p| p.unwrap()) + .map(|p| p.file_name().into_string().unwrap()) + .filter(|s| s.starts_with(FILE_PREFIX)) + .map(|filename| { + let file_path = dir_path.join(&filename); + let metadata = file_path.metadata().unwrap(); + let last_modified = time::OffsetDateTime::from(metadata.modified().unwrap()); + + SaveZipFile { + filename, + last_modified: last_modified.unix_timestamp().try_into().unwrap(), + } + }) + .collect()) +} + +pub fn build_save_zip( + pocket_path: &PathBuf, + save_paths: Vec<&str>, + dir_path: &str, + max_count: usize, +) -> Result<(), ()> { + let zip_path = Path::new(dir_path); + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + let filename = format!("{FILE_PREFIX}{timestamp}.zip"); + let zip_file_path = zip_path.join(filename); + let zip_file = File::create(zip_file_path).unwrap(); + + let mut zip = zip::ZipWriter::new(zip_file); + let options = FileOptions::default() + .compression_method(zip::CompressionMethod::Deflated) + .unix_permissions(0o755); + + let saves_path = pocket_path.join("Saves"); + + let mut buffer = Vec::new(); + for name in save_paths { + let path = saves_path.join(name); + let metadata = path.metadata().unwrap(); + let last_modified = time::OffsetDateTime::from(metadata.modified().unwrap()); + + let file_options = options.last_modified_time( + DateTime::from_date_and_time( + last_modified.year().try_into().unwrap(), + last_modified.month().try_into().unwrap(), + last_modified.day(), + last_modified.hour(), + last_modified.minute(), + last_modified.second(), + ) + .unwrap(), + ); + + if path.is_file() { + zip.start_file(name, file_options).unwrap(); + let mut f = File::open(path).unwrap(); + f.read_to_end(&mut buffer).unwrap(); + zip.write_all(&*buffer).unwrap(); + buffer.clear(); + } else { + zip.add_directory(name, options).unwrap(); + } + } + zip.finish().unwrap(); + + let files = read_save_zip_list(&PathBuf::from(zip_path)).unwrap(); + + if files.len() > max_count { + let oldest_file = files.iter().min().unwrap(); + let last_file_path = zip_path.join(&oldest_file.filename); + fs::remove_file(last_file_path).unwrap(); + } + Ok(()) +} + +fn remove_leading_slash(value: &str) -> &str { + if !value.starts_with("/") { + return value; + } + + let mut chars = value.chars(); + chars.next(); + chars.as_str() +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 00000000..506321b9 --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,65 @@ +{ + "build": { + "beforeDevCommand": "npm run dev", + "beforeBuildCommand": "npm run build", + "devPath": "http://localhost:1420", + "distDir": "../dist" + }, + "package": { + "productName": "Pocket Sync", + "version": "1.0.0" + }, + "tauri": { + "allowlist": { + "all": true + }, + "bundle": { + "active": true, + "category": "DeveloperTool", + "copyright": "", + "deb": { + "depends": [] + }, + "externalBin": [], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "identifier": "today.neil.pocket-sync", + "longDescription": "", + "macOS": { + "entitlements": null, + "exceptionDomain": "", + "frameworks": [], + "providerShortName": null, + "signingIdentity": null + }, + "resources": [], + "shortDescription": "", + "targets": "all", + "windows": { + "certificateThumbprint": null, + "digestAlgorithm": "sha256", + "timestampUrl": "" + } + }, + "security": { + "csp": null + }, + "updater": { + "active": false + }, + "windows": [ + { + "fullscreen": false, + "height": 600, + "resizable": true, + "title": "Pocket Sync", + "width": 800 + } + ] + } +} diff --git a/src/app.css b/src/app.css new file mode 100644 index 00000000..a89ebd15 --- /dev/null +++ b/src/app.css @@ -0,0 +1,7 @@ +.logo.vite:hover { + filter: drop-shadow(0 0 2em #747bff); +} + +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafb); +} diff --git a/src/app.tsx b/src/app.tsx new file mode 100644 index 00000000..a7164208 --- /dev/null +++ b/src/app.tsx @@ -0,0 +1,52 @@ +import "./font.css" +import "./app.css" +import { useRecoilState } from "recoil" +import { pocketPathAtom } from "./recoil/atoms" +import { Layout } from "./components/layout" +import React, { Suspense, useCallback, useState } from "react" +import { invokeOpenPocket } from "./utils/invokes" + +const Pocket = React.lazy(() => + import("./components/three/pocket").then((m) => ({ default: m.Pocket })) +) + +export const App = () => { + const [pocketPath, setPocketPath] = useRecoilState(pocketPathAtom) + const [attempts, setAttempts] = useState(0) + + const onOpenPocket = useCallback(async () => { + const result = await invokeOpenPocket() + setPocketPath(result) + if (result === null) { + setAttempts((a) => a + 1) + } else { + setAttempts(0) + } + }, [setPocketPath, setAttempts]) + + if (pocketPath) { + return + } + + return ( +
+

Pocket Sync

+ +
}> + + + + {attempts > 0 && ( +

+ {"That folder doesn't look like the Pocket's file system. Try again"} +

+ )} + +
+ +
+ + ) +} diff --git a/src/assets/AnalogueOS-Regular.woff b/src/assets/AnalogueOS-Regular.woff new file mode 100644 index 00000000..27ddec7f Binary files /dev/null and b/src/assets/AnalogueOS-Regular.woff differ diff --git a/src/assets/AnalogueOS-Regular.woff2 b/src/assets/AnalogueOS-Regular.woff2 new file mode 100644 index 00000000..fcc89c1b Binary files /dev/null and b/src/assets/AnalogueOS-Regular.woff2 differ diff --git a/src/components/about/index.css b/src/components/about/index.css new file mode 100644 index 00000000..218c781e --- /dev/null +++ b/src/components/about/index.css @@ -0,0 +1,40 @@ +.about { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + height: 100vh; + text-align: center; +} + + +.about__update-link{ + font-size: 2rem; + background-color: var(--green-colour); + padding: 20px; + border-radius: 25px; + white-space: nowrap; +} + +.about__top{ + flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: space-around; + /* width: 100%; */ + width: max-content; + text-align: center; + align-items: center; + gap: 10px; +} + +.about__info{ + background-color: var(--info-colour); + width: 100%; + max-height: fit-content; + flex-grow: 1; + justify-self: flex-end; + text-align: left; + padding: 0px 20px; + box-sizing: border-box; +} diff --git a/src/components/about/index.tsx b/src/components/about/index.tsx new file mode 100644 index 00000000..f58670fc --- /dev/null +++ b/src/components/about/index.tsx @@ -0,0 +1,79 @@ +import { Suspense, useMemo } from "react" +import { useRecoilValue } from "recoil" +import { GithubReleasesSelectorFamily } from "../../recoil/github/selectors" +import { + AppVersionSelector, + PocketSyncConfigSelector, +} from "../../recoil/selectors" +import { Link } from "../link" +import { Pocket } from "../three/pocket" +import { ProgressScreen } from "../three/progressScreen" +import { RandomScreenshotScreen } from "../three/randomScreenshotScreen" + +import "./index.css" + +export const About = () => { + const selfReleases = useRecoilValue( + GithubReleasesSelectorFamily({ + owner: "neil-morrison44", + repo: "pocket-sync", + }) + ) + + const AppVersion = useRecoilValue(AppVersionSelector) + + const updateAvailable = useMemo(() => { + return selfReleases[0].tag_name !== `v${AppVersion}` + }, [selfReleases, AppVersion]) + + return ( +
+
+
+

Pocket Sync

+ {`v${AppVersion}`} +
+ + {updateAvailable && ( + {`Update Available! ${selfReleases[0].tag_name}`} + )} + + } + > + + + } + /> +
+ +
+

Thanks to:

+ +
    +
  • + + {"https://github.com/joshcampbell191/openfpga-cores-inventory"} + +
  • + +
  • + + {"https://github.com/AbFarid/analogue-os-font"} + +
  • +
+
+
+ ) +} diff --git a/src/components/controls/index.css b/src/components/controls/index.css new file mode 100644 index 00000000..f7160cf2 --- /dev/null +++ b/src/components/controls/index.css @@ -0,0 +1,65 @@ +.controls{ + display: flex; + justify-content: space-between; + font-size: 1.125rem; + background-color: var(--info-colour); + position: sticky; + top: 0; + z-index: 100; +} + +.controls__item{ + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + padding: 10px 20px; + accent-color: white; + + &:hover{ + background-color: var(--hover-colour); + } +} + + +.controls__item--back::before{ + content: ""; + display: block; + width: 10px; + height: 10px; + aspect-ratio: 1 / 1; + border: 1px solid white; + border-right-color: transparent; + border-bottom-color: transparent; + transform: rotate(-45deg); + margin-right: 5px; +} + +.controls__item--checkbox{ + display: flex; + gap: 0.2em; + align-items: center; +} + + +.controls__search-input{ + border-radius: 8px; + border: 1px solid transparent; + padding: 2px 10px; + font-size: 1em; + font-weight: 500; + font-family: inherit; + width: 200px; + transition: border-color 0.25s; +} + +.controls__item--select{ + display: flex; + gap: 5px; + align-items: center; + font-size: 1.125rem; + + & > select { + font-size: 1.125rem; + } +} diff --git a/src/components/controls/index.tsx b/src/components/controls/index.tsx new file mode 100644 index 00000000..17c01315 --- /dev/null +++ b/src/components/controls/index.tsx @@ -0,0 +1,115 @@ +import "./index.css" + +type Control = { + text: string + type: "button" | "back-button" | "checkbox" | "select" | "search" +} & ( + | { + type: "button" + onClick: () => void + } + | { + type: "back-button" + onClick: () => void + } + | { + type: "checkbox" + checked: boolean + onChange: (checked: boolean) => void + } + | { + type: "select" + options: string[] + selected: string + onChange: (value: string) => void + } + | { + type: "search" + value: string + onChange: (value: string) => void + } +) + +type ControlProps = { + controls: (Control | null | undefined | "")[] +} + +export const Controls = ({ controls }: ControlProps) => { + return ( +
+ {controls.map((control) => { + if (!control) return null + switch (control.type) { + case "search": + return ( +
+ control.onChange(target.value)} + autoComplete="off" + value={control.value} + spellCheck={false} + /> +
+ ) + case "select": + return ( +
+ {control.text} + +
+ ) + case "button": + return ( +
+ {control.text} +
+ ) + case "back-button": + return ( +
+ {"Back to List"} +
+ ) + case "checkbox": + return ( + + ) + } + })} +
+ ) +} diff --git a/src/components/cores/index.css b/src/components/cores/index.css new file mode 100644 index 00000000..91cd13f0 --- /dev/null +++ b/src/components/cores/index.css @@ -0,0 +1,51 @@ +.cores__platform-image { + width: 100%; +} + +.cores__info-blurb{ + background-color: var(--info-colour); + padding: 10px; + display: flex; + gap: 5px; + flex-direction: column; + justify-content: space-between; + flex-grow: 1; +} + +.cores__info-blurb-name{ + font-weight: bold; +} + +.cores__author-tag{ + display: flex; + align-items: center; + gap: 10px; +} + +.cores__author-tag-image{ + width: 24px; + height: 24px; +} + +.cores__item{ + display: flex; + flex-direction: column; + cursor: pointer; + + &:hover, &:focus { + transform: scale(1.1); + } +} + +.cores__item--not-installed{ + background-color: var(--info-colour); + justify-content: space-between; + padding: 10px; + font-weight: bold; + cursor: pointer; +} + +.cores__not-installed-item-id{ + font-weight: normal; + font-size: 0.825rem; +} diff --git a/src/components/cores/index.tsx b/src/components/cores/index.tsx new file mode 100644 index 00000000..747b0005 --- /dev/null +++ b/src/components/cores/index.tsx @@ -0,0 +1,148 @@ +import { Suspense, useMemo, useState } from "react" +import { useRecoilCallback, useRecoilValue } from "recoil" +import { useCategoryLookup } from "../../hooks/useCategoryLookup" +import { useSaveScroll } from "../../hooks/useSaveScroll" +import { + fileSystemInvalidationAtom, + inventoryInvalidationAtom, +} from "../../recoil/atoms" +import { CateogryListselector } from "../../recoil/inventory/selectors" +import { CoreInventorySelector } from "../../recoil/inventory/selectors" +import { coresListSelector } from "../../recoil/selectors" +import { Controls } from "../controls" +import { Grid } from "../grid" +import { Loader } from "../loader" +import { Tip } from "../tip" +import { CoreInfo } from "./info" +import { CoreItem } from "./item" + +export const Cores = () => { + const [selectedCore, setSelectedCore] = useState(null) + const coresList = useRecoilValue(coresListSelector) + const coreInventory = useRecoilValue(CoreInventorySelector) + const { pushScroll, popScroll } = useSaveScroll() + const [searchQuery, setSearchQuery] = useState("") + const [filterCategory, setFilterCategory] = useState("All") + const lookupCategory = useCategoryLookup() + + const refresh = useRecoilCallback(({ set }) => () => { + set(inventoryInvalidationAtom, Date.now()) + set(fileSystemInvalidationAtom, Date.now()) + }) + + const notInstalledCores = useMemo(() => { + return coreInventory.data + .filter(({ identifier }) => !coresList.includes(identifier)) + .filter(({ release, prerelease }) => { + if (filterCategory === "All") return true + + if (release?.platform.category === filterCategory) return true + if (prerelease?.platform.category === filterCategory) return true + return false + }) + .filter((core) => + core.identifier.toLowerCase().includes(searchQuery.toLowerCase()) + ) + }, [searchQuery, filterCategory, coresList, coreInventory]) + + const sortedList = useMemo( + () => + [...coresList] + .sort((a, b) => { + const [authorA, coreA] = a.split(".") + const switchedA = `${coreA}.${authorA}` + + const [authorB, coreB] = b.split(".") + const switchedB = `${coreB}.${authorB}` + + return switchedA.localeCompare(switchedB) + }) + .filter((core) => { + if (filterCategory === "All") return true + return lookupCategory(core) === filterCategory + }) + .filter((core) => + core.toLowerCase().includes(searchQuery.toLowerCase()) + ), + [searchQuery, filterCategory, coresList] + ) + + const categoryList = useRecoilValue(CateogryListselector) + + if (selectedCore) { + return ( + { + setSelectedCore(null) + popScroll() + }} + /> + ) + } + + return ( +
+ setSearchQuery(v), + }, + { + type: "button", + text: "Refresh", + onClick: refresh, + }, + { + type: "select", + options: categoryList, + selected: filterCategory, + text: "Category", + onChange: (v) => setFilterCategory(v), + }, + ]} + /> +

{`Installed (${sortedList.length})`}

+ + {sortedList.map((core) => ( + } key={core}> + { + pushScroll() + setSelectedCore(core) + }} + /> + + ))} + + +

{`Available (${notInstalledCores.length})`}

+ + {notInstalledCores.map(({ identifier: core, platform }) => ( + } key={core}> +
{ + pushScroll() + setSelectedCore(core) + }} + > +
{platform}
+
{core}
+
+
+ ))} +
+ + + { + "You can also install cores (or anything else in a zip) by dragging the .zip into this window" + } + +
+ ) +} diff --git a/src/components/cores/info/index.css b/src/components/cores/info/index.css new file mode 100644 index 00000000..04b35e03 --- /dev/null +++ b/src/components/cores/info/index.css @@ -0,0 +1,81 @@ +.core-info{ + display: flex; + flex-direction: column; + min-height: 100vh; +} + +.core-info__image{ + width: 100%; + image-rendering: pixelated; +} + + +.core-info__title{ + padding: 0px 20px; + font-size: 2rem; +} + +.core-info__info{ + background-color: var(--info-colour); + padding: 10px; + display: flex; + gap: 5px; + flex-direction: column; + flex-grow: 1; +} + +.core-info__info-row{ + display: flex; + align-items: center; + gap: 10px; + grid-column: 1; +} + +.core-info__info-row--right{ + grid-column: 2; +} + +.core-info__info-grid{ + display: grid; + gap: inherit; + grid-template-columns: 1fr auto; +} + +.core-info__author-tag{ + display: inline-flex; + gap: 10px; + justify-content: center; + align-items: center; + + image-rendering: pixelated; +} + +.core-info__supports-bubbles{ + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.core-info__supports { + white-space: nowrap; + background-color: var(--light-colour); + padding: 0 5px; + border-radius: 5px; +} + +.core-info__platforms{ + padding: 10px 0; + display: flex; + flex-direction: column; + gap: 10px; +} + +.core-info__platform-loader{ + width: 100px; + aspect-ratio: 4 / 2; + border-radius: 15px; +} + +.core-info__supports--false{ + opacity: 0.2; +} diff --git a/src/components/cores/info/index.tsx b/src/components/cores/info/index.tsx new file mode 100644 index 00000000..0f0b1c2e --- /dev/null +++ b/src/components/cores/info/index.tsx @@ -0,0 +1,19 @@ +import { useRecoilValue } from "recoil" +import { coresListSelector } from "../../../recoil/selectors" +import { InstalledCoreInfo } from "./installed" +import { NotInstalledCoreInfo } from "./notInstalled" + +type CoreInfoProps = { + coreName: string + onBack: () => void +} + +export const CoreInfo = (props: CoreInfoProps) => { + const coresList = useRecoilValue(coresListSelector) + + if (coresList.includes(props.coreName)) { + return + } else { + return + } +} diff --git a/src/components/cores/info/installOptions/index.css b/src/components/cores/info/installOptions/index.css new file mode 100644 index 00000000..489a0c64 --- /dev/null +++ b/src/components/cores/info/installOptions/index.css @@ -0,0 +1,49 @@ +.install-options__paths{ + flex-grow: 1; + overflow: auto; + background-color: var(--info-colour); + border-radius: 10px; + box-sizing: border-box; + padding: 10px; +} + +.install-options__controls { + display: flex; + justify-content: space-around; +} + +.install-options__tree-node{ + margin-left: 20px; + display: flex; + flex-direction: column; +} + +.install-options__tree-node-info{ + display: flex; + gap: 5px; + align-items: center; +} + +.install-options__progress{ + width: 100%; + accent-color: unset; +} + +.install-options__tree-node-name{ + display: flex; + gap: inherit; + cursor: pointer; + align-items: center; +} + +.install-options__tree-arrow{ + display: inline-block; + width: 12px; + height: 12px; + background-color: white; + clip-path: polygon(0% 0%, 50% 100%, 100% 0%); +} + +.install-options__tree-arrow--collapsed { + transform: rotate(-90deg); +} diff --git a/src/components/cores/info/installOptions/index.tsx b/src/components/cores/info/installOptions/index.tsx new file mode 100644 index 00000000..93536c97 --- /dev/null +++ b/src/components/cores/info/installOptions/index.tsx @@ -0,0 +1,187 @@ +import { emit, listen } from "@tauri-apps/api/event" +import { useCallback, useEffect, useMemo, useState } from "react" +import { InstallDetails } from "../../../../types" +import { Modal } from "../../../modal" + +import "./index.css" + +type InstallOptionsProps = { + details: InstallDetails +} + +export const InstallOptions = ({ details }: InstallOptionsProps) => { + const [allowedFiles, setAllowedFiles] = useState( + details.files.map(({ path }) => path) + ) + + const toggleFile = useCallback( + (path: string) => { + setAllowedFiles((f) => { + if (f.includes(path)) { + return f.filter((p) => p !== path) + } else { + return [...f, path] + } + }) + }, + [setAllowedFiles] + ) + + const [progress, setProgress] = useState<{ + max: number + value: number + } | null>(null) + + useEffect(() => { + const unlisten = listen<{ max: number; value: number }>( + "core-progress", + ({ payload }) => { + setProgress(payload) + } + ) + + return () => { + unlisten.then((l) => l()) + } + }, []) + + const confirm = useCallback(() => { + emit("install-confirmation", { + paths: allowedFiles, + allow: true, + }) + }, [allowedFiles]) + + const cancel = useCallback(() => { + emit("install-confirmation", { + paths: [], + allow: false, + }) + }, []) + + const tree = useMemo(() => { + const sortedFiles = [...details.files].sort( + ({ path: pathA }, { path: pathB }) => pathA.localeCompare(pathB) + ) + + return sortedFiles.reduce((prev, curr) => { + const newTree: FileTreeNode[] = [...prev] + const fileBits = curr.path.split("/") + let treeNode = newTree + + for (let index = 0; index < fileBits.length; index++) { + const element = fileBits[index] + if (element === "") continue + if (!treeNode.find(({ name }) => name === element)) { + treeNode.push({ + name: element, + full: curr.path, + exists: curr.exists, + is_dir: index !== fileBits.length - 1, + children: [], + }) + } + + treeNode = treeNode.find(({ name }) => name === element)?.children || [] + } + + return newTree + }, [] as FileTreeNode[]) + }, [details.files]) + + return ( + +

{"Install Core"}

+ {!progress && ( +
+ {tree.map((node) => ( + + ))} +
+ )} + + {progress && ( + <> +

{`${((progress.value / progress.max) * 100).toFixed(0)}%`}

+ + + )} + + {!progress && ( +
+ + +
+ )} +
+ ) +} + +type FileTreeNode = { + name: string + full: string + exists: boolean + is_dir: boolean + children: FileTreeNode[] +} + +const TreeNode = ({ + node, + allowed, + defaultExpanded = false, + toggleFile, +}: { + node: FileTreeNode + defaultExpanded?: boolean + allowed: string[] + toggleFile: (path: string) => void +}) => { + const [expanded, setExpanded] = useState(defaultExpanded) + + return ( +
+
+ {!node.is_dir && ( + toggleFile(node.full)} + > + )} +
setExpanded((e) => !e)} + > + {node.is_dir && ( +
+ )} + {node.name} + {node.is_dir ? "/" : ""} +
+
+ + {expanded && + node.children.map((n) => ( + + ))} +
+ ) +} diff --git a/src/components/cores/info/installed.tsx b/src/components/cores/info/installed.tsx new file mode 100644 index 00000000..c4aa1f3a --- /dev/null +++ b/src/components/cores/info/installed.tsx @@ -0,0 +1,192 @@ +import { platform } from "os" +import { useRecoilValue } from "recoil" +import { + CoreAuthorImageSelectorFamily, + CoreInfoSelectorFamily, +} from "../../../recoil/selectors" +import { + CoreInventorySelector, + DownloadURLSelectorFamily, +} from "../../../recoil/inventory/selectors" +import { Controls } from "../../controls" +import { Link } from "../../link" + +import "./index.css" +import { PlatformImage } from "../platformImage" +import { useInventoryItem } from "../../../hooks/useInventoryItem" +import { Releases } from "./releases" +import { Version } from "../version" +import { useUninstallCore } from "../../../hooks/useUninstallCore" +import { useInstallCore } from "../../../hooks/useInstallCore" +import { ReactNode, Suspense, useState } from "react" +import { CorePlatformInfo } from "./platform" +import { Loader } from "../../loader" +import { SponsorLinks } from "./sponsorLinks" +import { RequiredFiles } from "./requiredFiles" +import { LoadRequiredFiles } from "./loadRequiredFiles" + +type CoreInfoProps = { + coreName: string + onBack: () => void +} + +export const InstalledCoreInfo = ({ coreName, onBack }: CoreInfoProps) => { + const coreInfo = useRecoilValue(CoreInfoSelectorFamily(coreName)) + const authorImageSrc = useRecoilValue(CoreAuthorImageSelectorFamily(coreName)) + const uninstall = useUninstallCore() + const { installCore } = useInstallCore() + const inventoryItem = useInventoryItem(coreName) + const downloadUrl = useRecoilValue(DownloadURLSelectorFamily(coreName)) + + const [requiredFilesOpen, setRequiredFilesOpen] = useState(false) + + return ( +
+ uninstall(coreName), + }, + { + type: "button", + text: "Required Files", + onClick: () => setRequiredFilesOpen(true), + }, + downloadUrl && { + type: "button", + text: "Update", + onClick: () => installCore(coreName, downloadUrl), + }, + ]} + /> + + {requiredFilesOpen && ( + setRequiredFilesOpen(false)} + /> + )} + +

{coreInfo.core.metadata.shortname}

+ {coreInfo.core.metadata.platform_ids.map((platformId) => ( + + ))} + +
+

{coreInfo.core.metadata.description}

+ +
+
+ {"Version:"} + +
+ +
+ {"Author:"} +
+ + {coreInfo.core.metadata.author} +
+
+ + {inventoryItem?.sponsor && ( +
+ {"Sponsor:"} + +
+ )} + + {coreInfo.core.metadata.url && ( +
+ {"URL:"} + + + {coreInfo.core.metadata.url} + +
+ )} + + + + {coreInfo.core.metadata.date_release && ( +
+ {"Release Date:"} + + {coreInfo.core.metadata.date_release} +
+ )} +
+ +
+ {"Supports:"} +
+ + {"Save States / Sleep"} + + + + {"Dock"} + + + + {"Dock (Analog)"} + + + + {"Cartridges"} + +
+
+ +
+ {"Platforms:"} + } + > +
+ {coreInfo.core.metadata.platform_ids.map((id) => ( + + ))} +
+
+
+ {inventoryItem && inventoryItem.repository.platform === "github" && ( + + )} +
+
+ ) +} + +type SupportsBubbleProps = { + children: ReactNode + supports: boolean +} + +const SupportsBubble = ({ supports, children }: SupportsBubbleProps) => ( +
+ {children} +
+) diff --git a/src/components/cores/info/loadRequiredFiles/index.css b/src/components/cores/info/loadRequiredFiles/index.css new file mode 100644 index 00000000..f5f83e13 --- /dev/null +++ b/src/components/cores/info/loadRequiredFiles/index.css @@ -0,0 +1,40 @@ +.load-required-files{ + width: max-content; + height: max-content; + max-height: 80vh; + + min-width: 50vw; + min-height: 50vw; +} + +.load-required-files__files { + background-color: var(--info-colour); + padding: 10px 20px; + display: flex; + flex-direction: column; + gap: 10px; + border-radius: 10px; + overflow: auto; +} + +.load-required-files__row{ + display: flex; + + align-items: center; + gap: 0.5em; + + & > pre { + margin-top: 0; + margin-bottom: 0; + } +} + +.load-required-files__row--exists{ + opacity: 0.5; +} + +.load-required-files__buttons{ + display: flex; + justify-content: space-between; + gap: 20px; +} diff --git a/src/components/cores/info/loadRequiredFiles/index.tsx b/src/components/cores/info/loadRequiredFiles/index.tsx new file mode 100644 index 00000000..b03c957d --- /dev/null +++ b/src/components/cores/info/loadRequiredFiles/index.tsx @@ -0,0 +1,81 @@ +import { useRecoilValue } from "recoil" +import { useInstallRequiredFiles } from "../../../../hooks/useInstallRequiredFiles" +import { + PocketSyncConfigSelector, + RequiredFileInfoSelectorFamily, +} from "../../../../recoil/selectors" +import { Modal } from "../../../modal" +import { Progress } from "../../../progress" + +import "./index.css" + +type LoadRequiredFilesProps = { + coreName: string + onClose: () => void +} + +export const LoadRequiredFiles = ({ + coreName, + onClose, +}: LoadRequiredFilesProps) => { + const requiredFiles = useRecoilValue(RequiredFileInfoSelectorFamily(coreName)) + const pocketSyncConfig = useRecoilValue(PocketSyncConfigSelector) + const { installRequiredFiles, progress } = useInstallRequiredFiles(onClose) + + return ( + +

{"Required Files"}

+ + {progress && } + + {!progress && ( + <> +
+ {requiredFiles.map((r) => { + return ( +
+ Put
{`"${r.filename}"`}
in{" "} +
{`"${r.path}"`}
+
+ ) + })} +
+ + {!pocketSyncConfig.archive_url && ( +

+ { + "Please view the `Settings` pane for more options with required files" + } +

+ )} +
+ + + {pocketSyncConfig.archive_url && ( + + )} + + {pocketSyncConfig.archive_url && ( + + )} +
+ + )} +
+ ) +} diff --git a/src/components/cores/info/notInstalled.tsx b/src/components/cores/info/notInstalled.tsx new file mode 100644 index 00000000..9d92a649 --- /dev/null +++ b/src/components/cores/info/notInstalled.tsx @@ -0,0 +1,73 @@ +import { useMemo } from "react" +import { useRecoilValue } from "recoil" +import { useInstallCore } from "../../../hooks/useInstallCore" +import { useInventoryItem } from "../../../hooks/useInventoryItem" +import { DownloadURLSelectorFamily } from "../../../recoil/inventory/selectors" +import { Controls } from "../../controls" +import { Link } from "../../link" +import { Releases } from "./releases" + +type NotInstalledCoreInfoProps = { + onBack: () => void + coreName: string +} + +export const NotInstalledCoreInfo = ({ + coreName, + onBack, +}: NotInstalledCoreInfoProps) => { + const inventoryItem = useInventoryItem(coreName) + + const url = useMemo(() => { + if (inventoryItem?.repository.platform !== "github") return null + return `https://github.com/${inventoryItem.repository.owner}/${inventoryItem.repository.name}` + }, [inventoryItem]) + + const download_url = useRecoilValue(DownloadURLSelectorFamily(coreName)) + const { installCore } = useInstallCore() + + return ( +
+ { + installCore(coreName, download_url) + }, + }, + ]} + /> + + {!inventoryItem &&
{`${coreName} not in cores inventory`}
} + + {inventoryItem && ( + <> +

{inventoryItem.platform}

+
+
+ {inventoryItem.identifier} +
+ + {url && ( +
+ {"URL:"} + {url} +
+ )} + + {inventoryItem.repository.platform === "github" && ( + + )} +
+ + )} +
+ ) +} diff --git a/src/components/cores/info/platform/index.css b/src/components/cores/info/platform/index.css new file mode 100644 index 00000000..8bb004da --- /dev/null +++ b/src/components/cores/info/platform/index.css @@ -0,0 +1,33 @@ +.cores__platform-info{ + border-radius: 12px; + background-color: var(--background-colour); + display: flex; + grid-template-columns: max-content min-content; + gap: 15px; + overflow: hidden; + + & > *{ + padding: 10px 0; + } + + & > *:first-child{ + padding-left: 15px; + } + + & > *:last-child{ + padding-right: 15px; + } +} + +.cores__platform-info-name{ + font-size: 1.25rem; +} + +.cores__platform-info-cateogry { + border-right: 1px solid white; + padding-right: 15px; + box-sizing: border-box; + background-color: var(--light-colour); + display: flex; + align-items: center; +} diff --git a/src/components/cores/info/platform/index.tsx b/src/components/cores/info/platform/index.tsx new file mode 100644 index 00000000..8834ad5c --- /dev/null +++ b/src/components/cores/info/platform/index.tsx @@ -0,0 +1,39 @@ +import { useMemo } from "react" +import { useRecoilValue } from "recoil" +import { PlatformInfoSelectorFamily } from "../../../../recoil/selectors" +import { PlatformId } from "../../../../types" +import { Link } from "../../../link" + +import "./index.css" + +const HARD_TO_FIND_THINGS = ["Genesis", "Dominos", "Green Beret"] + +type CorePlatformInfoProps = { + platformId: PlatformId +} + +export const CorePlatformInfo = ({ platformId }: CorePlatformInfoProps) => { + const { platform } = useRecoilValue(PlatformInfoSelectorFamily(platformId)) + + const wikiLink = useMemo(() => { + const searchTerm = HARD_TO_FIND_THINGS.includes(platform.name) + ? `${platform.manufacturer} ${platform.name}` + : platform.name + + return `https://en.wikipedia.org/wiki/Special:Search?go=Go&search=${window.encodeURIComponent( + searchTerm + )}` + }, [platform]) + + return ( +
+
{platform.category}
+ {platform.name} + +
{`${platform.manufacturer}, ${platform.year}`}
+ + {"Wikipedia"} + +
+ ) +} diff --git a/src/components/cores/info/releases.css b/src/components/cores/info/releases.css new file mode 100644 index 00000000..f96944a3 --- /dev/null +++ b/src/components/cores/info/releases.css @@ -0,0 +1,48 @@ +.releases__title{ + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + font-weight: bold; + font-size: 1.25rem; +} + + +.releases__body{ + border-left: 2px solid white; + padding-left: 10px; + box-sizing: border-box; + margin-left: 10px; +} + + +.releases__body--collapsed { + max-height: 110px; + overflow: hidden; + position: relative; + cursor: pointer; + + &::after{ + content: ""; + position: absolute; + display: block; + bottom: 0; + width: 100%; + height: 100%; + + background: linear-gradient(transparent, var(--info-colour)); + } + + & * { + pointer-events: none; + } +} + +.releases__more-button{ + cursor: pointer; + font-size: 1.25rem; + padding: 10px; + &:hover{ + text-decoration: underline; + } +} diff --git a/src/components/cores/info/releases.tsx b/src/components/cores/info/releases.tsx new file mode 100644 index 00000000..e68c8348 --- /dev/null +++ b/src/components/cores/info/releases.tsx @@ -0,0 +1,89 @@ +import { useRecoilValue } from "recoil" +import { InventoryItem } from "../../../types" +import ReactMarkdown from "react-markdown" +import remarkGfm from "remark-gfm" +import { useState } from "react" +import { Link } from "../../link" +import { GithubReleasesSelectorFamily } from "../../../recoil/github/selectors" + +import "./releases.css" + +type ReleasesProps = { + inventoryItem: InventoryItem +} + +const INITAL_COUNT = 1 + +export const Releases = ({ inventoryItem }: ReleasesProps) => { + if (inventoryItem.repository.platform !== "github") { + throw new Error("Can't show non-github releases") + } + + const [showAll, setShowAll] = useState(false) + + const githubReleases = useRecoilValue( + GithubReleasesSelectorFamily({ + owner: inventoryItem.repository.owner, + repo: inventoryItem.repository.name, + }) + ) + + return ( +
+ Release History: + {githubReleases + .slice(0, showAll ? Infinity : INITAL_COUNT) + .map(({ id, name, body, tag_name, created_at }) => ( +
+
+ {tag_name} - {name} +
{new Date(created_at).toLocaleString()}
+
+ + +
+ ))} + + {!showAll && githubReleases.length > INITAL_COUNT && ( +
setShowAll(true)} + > + {"Show previous releases"} +
+ )} +
+ ) +} + +type ReleaseBodyProps = { + body: string +} + +const ReleaseBody = ({ body }: ReleaseBodyProps) => { + const [collapsed, setCollapsed] = useState(true) + + return ( +
setCollapsed(false)} + > + {children}, + }} + > + {body} + +
+ ) +} diff --git a/src/components/cores/info/requiredFiles/index.css b/src/components/cores/info/requiredFiles/index.css new file mode 100644 index 00000000..67f91d03 --- /dev/null +++ b/src/components/cores/info/requiredFiles/index.css @@ -0,0 +1,10 @@ +.required-files{ + white-space: nowrap; + background-color: var(--light-colour); + padding: 0 5px; + border-radius: 5px; +} + +.required-files--missing { + background-color: var(--red-colour); +} diff --git a/src/components/cores/info/requiredFiles/index.tsx b/src/components/cores/info/requiredFiles/index.tsx new file mode 100644 index 00000000..78d6fe90 --- /dev/null +++ b/src/components/cores/info/requiredFiles/index.tsx @@ -0,0 +1,46 @@ +import { useMemo } from "react" +import { useRecoilValue } from "recoil" +import { RequiredFileInfoSelectorFamily } from "../../../../recoil/selectors" + +import "./index.css" + +type RequiredFilesProps = { + coreName: string + ignoreInstance?: boolean +} + +export const RequiredFiles = ({ + coreName, + ignoreInstance, +}: RequiredFilesProps) => { + const requiredFiles = useRecoilValue(RequiredFileInfoSelectorFamily(coreName)) + + const filteredRequiredFiles = useMemo(() => { + if (!ignoreInstance) return requiredFiles + + return requiredFiles.filter(({ type }) => type !== "instance") + }, [requiredFiles]) + + const foundFiles = useMemo( + () => filteredRequiredFiles.filter(({ exists }) => exists), + [filteredRequiredFiles] + ) + + const full = useMemo( + () => filteredRequiredFiles.every(({ exists }) => exists), + [filteredRequiredFiles] + ) + + if (filteredRequiredFiles.length === 0) return null + + return ( +
+ {"Required Files:"} +
{`${foundFiles.length} / ${filteredRequiredFiles.length} Files`}
+
+ ) +} diff --git a/src/components/cores/info/sponsorLinks/index.css b/src/components/cores/info/sponsorLinks/index.css new file mode 100644 index 00000000..0a307691 --- /dev/null +++ b/src/components/cores/info/sponsorLinks/index.css @@ -0,0 +1,9 @@ +.sponsor-links{ + display: flex; + flex-direction: column; + gap: 5px; +} + +.sponsor-links__link{ + word-break: break-all; +} diff --git a/src/components/cores/info/sponsorLinks/index.tsx b/src/components/cores/info/sponsorLinks/index.tsx new file mode 100644 index 00000000..2e43547c --- /dev/null +++ b/src/components/cores/info/sponsorLinks/index.tsx @@ -0,0 +1,27 @@ +import { useMemo } from "react" +import { InventoryItem } from "../../../../types" +import { Link } from "../../../link" + +import "./index.css" + +type SponsorLinkProps = { + links: Required["sponsor"] +} + +export const SponsorLinks = ({ links }: SponsorLinkProps) => { + const sponsorTypes = useMemo(() => Object.keys(links || {}), [links]) + + return ( +
+ {sponsorTypes.map((sponsorKey) => ( + + {links[sponsorKey]} + + ))} +
+ ) +} diff --git a/src/components/cores/item.tsx b/src/components/cores/item.tsx new file mode 100644 index 00000000..c77d415e --- /dev/null +++ b/src/components/cores/item.tsx @@ -0,0 +1,44 @@ +import { useRecoilValue } from "recoil" +import { + CoreAuthorImageSelectorFamily, + CoreInfoSelectorFamily, +} from "../../recoil/selectors" +import { PlatformImage } from "./platformImage" + +import "./index.css" +import { Version } from "./version" + +type CoreItemProps = { + coreName: string + onClick: () => void +} + +export const CoreItem = ({ coreName, onClick }: CoreItemProps) => { + const coreInfo = useRecoilValue(CoreInfoSelectorFamily(coreName)) + const imageSrc = useRecoilValue(CoreAuthorImageSelectorFamily(coreName)) + + return ( +
+ {coreInfo.core.metadata.platform_ids.map((platformId) => ( + + ))} + +
+
+ {coreInfo.core.metadata.shortname} +
+ + + +
+ + {coreInfo.core.metadata.author} +
+
+
+ ) +} diff --git a/src/components/cores/platformImage.tsx b/src/components/cores/platformImage.tsx new file mode 100644 index 00000000..471f258f --- /dev/null +++ b/src/components/cores/platformImage.tsx @@ -0,0 +1,15 @@ +import { useRecoilValue } from "recoil" +import { PlatformImageSelectorFamily } from "../../recoil/selectors" +import { PlatformId } from "../../types" + +type PlatformImageProps = { + platformId: PlatformId + className?: string +} +export const PlatformImage = ({ + platformId, + className, +}: PlatformImageProps) => { + const imageSrc = useRecoilValue(PlatformImageSelectorFamily(platformId)) + return +} diff --git a/src/components/cores/version/index.css b/src/components/cores/version/index.css new file mode 100644 index 00000000..3bfcc84a --- /dev/null +++ b/src/components/cores/version/index.css @@ -0,0 +1,12 @@ +.version { + display: flex; + gap: 5px; + justify-content: space-between; + align-items: flex-start; +} + +.version__update{ + background-color: var(--green-colour); + padding: 0px 10px; + border-radius: 10px; +} diff --git a/src/components/cores/version/index.tsx b/src/components/cores/version/index.tsx new file mode 100644 index 00000000..cbb8f366 --- /dev/null +++ b/src/components/cores/version/index.tsx @@ -0,0 +1,45 @@ +import { useMemo } from "react" +import { useRecoilValue } from "recoil" +import { CoreInfoSelectorFamily } from "../../../recoil/selectors" +import { CoreInventorySelector } from "../../../recoil/inventory/selectors" + +import "./index.css" + +type VersionProps = { + coreName: string +} + +export const Version = ({ coreName }: VersionProps) => { + const coreInfo = useRecoilValue(CoreInfoSelectorFamily(coreName)) + const coreInventory = useRecoilValue(CoreInventorySelector) + + const updateAvailable = useMemo(() => { + // this isn't very good yet + const inventoryCore = coreInventory.data.find( + ({ identifier }) => identifier === coreName + ) + + if (!inventoryCore?.release) return null + + const { tag_name } = inventoryCore.release + const metadataVersion = coreInfo.core.metadata.version + + if (tag_name !== metadataVersion) { + if (tag_name.includes(metadataVersion)) { + return null + } + return inventoryCore.release.tag_name + } + + return null + }, [coreInfo.core.metadata.version, coreInventory]) + + return ( +
+ {coreInfo.core.metadata.version} + {updateAvailable && ( +
{updateAvailable}
+ )} +
+ ) +} diff --git a/src/components/disconnections/index.tsx b/src/components/disconnections/index.tsx new file mode 100644 index 00000000..5e613a3e --- /dev/null +++ b/src/components/disconnections/index.tsx @@ -0,0 +1,31 @@ +import { listen } from "@tauri-apps/api/event" +import { useEffect } from "react" +import { useSetRecoilState } from "recoil" +import { fileSystemInvalidationAtom, pocketPathAtom } from "../../recoil/atoms" + +export const Disconnections = () => { + const setPocketPath = useSetRecoilState(pocketPathAtom) + const setFileSystemInvalidation = useSetRecoilState( + fileSystemInvalidationAtom + ) + + useEffect(() => { + const unlisten = listen<{ connected: boolean }>( + "pocket-connection", + ({ payload }) => { + if (!payload.connected) { + setPocketPath(null) + setTimeout(() => { + setFileSystemInvalidation(Date.now()) + }, 50) + } + } + ) + + return () => { + unlisten.then((l) => l()) + } + }, []) + + return null +} diff --git a/src/components/games/gameCount.tsx b/src/components/games/gameCount.tsx new file mode 100644 index 00000000..dc907792 --- /dev/null +++ b/src/components/games/gameCount.tsx @@ -0,0 +1,16 @@ +import { useRecoilValue } from "recoil" +import { FileCountSelectorFamily } from "../../recoil/selectors" + +export const GameCount = ({ + platformId, + extensions, +}: { + platformId: string + extensions: string[] +}) => { + const count = useRecoilValue( + FileCountSelectorFamily({ path: `Assets/${platformId}`, extensions }) + ) + + return
{`${count.toLocaleString()} Games`}
+} diff --git a/src/components/games/index.tsx b/src/components/games/index.tsx new file mode 100644 index 00000000..c20934a5 --- /dev/null +++ b/src/components/games/index.tsx @@ -0,0 +1,84 @@ +import { Suspense, useMemo, useState } from "react" +import { useRecoilCallback, useRecoilValue } from "recoil" +import { useCategoryLookup } from "../../hooks/useCategoryLookup" +import { useSaveScroll } from "../../hooks/useSaveScroll" +import { + fileSystemInvalidationAtom, + inventoryInvalidationAtom, +} from "../../recoil/atoms" +import { CateogryListselector } from "../../recoil/inventory/selectors" +import { coresListSelector } from "../../recoil/selectors" +import { Controls } from "../controls" +import { Grid } from "../grid" +import { Loader } from "../loader" +import { CoreFolderItem } from "./item" + +export const Games = () => { + const coresList = useRecoilValue(coresListSelector) + const [searchQuery, setSearchQuery] = useState("") + const [filterCategory, setFilterCategory] = useState("All") + const lookupCategory = useCategoryLookup() + + const refresh = useRecoilCallback(({ set }) => () => { + set(inventoryInvalidationAtom, Date.now()) + set(fileSystemInvalidationAtom, Date.now()) + }) + + const sortedList = useMemo( + () => + [...coresList] + .sort((a, b) => { + const [authorA, coreA] = a.split(".") + const switchedA = `${coreA}.${authorA}` + + const [authorB, coreB] = b.split(".") + const switchedB = `${coreB}.${authorB}` + + return switchedA.localeCompare(switchedB) + }) + .filter((core) => { + if (filterCategory === "All") return true + return lookupCategory(core) === filterCategory + }) + .filter((core) => + core.toLowerCase().includes(searchQuery.toLowerCase()) + ), + [searchQuery, filterCategory, coresList] + ) + + const categoryList = useRecoilValue(CateogryListselector) + + return ( +
+ setSearchQuery(v), + }, + { + type: "button", + text: "Refresh", + onClick: refresh, + }, + { + type: "select", + options: categoryList, + selected: filterCategory, + text: "Category", + onChange: (v) => setFilterCategory(v), + }, + ]} + /> + + {sortedList.map((core) => ( + } key={core}> + + + ))} + +
+ ) +} diff --git a/src/components/games/item.tsx b/src/components/games/item.tsx new file mode 100644 index 00000000..ed217475 --- /dev/null +++ b/src/components/games/item.tsx @@ -0,0 +1,62 @@ +import { useMemo } from "react" +import { useRecoilValue } from "recoil" +import { pocketPathAtom } from "../../recoil/atoms" +import { + CoreInfoSelectorFamily, + DataJSONSelectorFamily, +} from "../../recoil/selectors" +import { decodeDataParams } from "../../utils/decodeDataParams" +import { PlatformImage } from "../cores/platformImage" +import { Link } from "../link" +import { GameCount } from "./gameCount" + +export const CoreFolderItem = ({ coreName }: { coreName: string }) => { + const info = useRecoilValue(CoreInfoSelectorFamily(coreName)) + const data = useRecoilValue(DataJSONSelectorFamily(coreName)) + const pocketPath = useRecoilValue(pocketPathAtom) + + const romsSlot = useMemo( + () => + data.data.data_slots + .filter(({ required, extensions }) => required && extensions) + .at(0), + [data] + ) + + const platformIds = useMemo(() => info.core.metadata.platform_ids, [info]) + + const paths = useMemo(() => { + if (!romsSlot || !platformIds) return [] + const coreSpecific = decodeDataParams(romsSlot.parameters)?.coreSpecific + + return platformIds.map( + (pId) => + `${pocketPath}/Assets/${pId}/${coreSpecific ? coreName : "common"}` + ) + }, [romsSlot, platformIds]) + + if (paths.length === 0) return null + + console.log({ paths }) + + return ( + <> + {info.core.metadata.platform_ids.map((platformId, index) => ( + + +
+ {coreName} + +
+ + ))} + + ) +} diff --git a/src/components/grid/index.css b/src/components/grid/index.css new file mode 100644 index 00000000..a7ea3ccb --- /dev/null +++ b/src/components/grid/index.css @@ -0,0 +1,22 @@ +.grid { + display: grid; + grid-auto-flow: row; + grid-template-columns: repeat(2, minmax(100px, 1fr)); + gap: 15px; + padding: 10px; + align-items: stretch; + justify-items: stretch; + grid-template-rows: repeat(auto-fill, minmax(100px, 1fr)); + + @media (min-width: 640px) { + grid-template-columns: repeat(3, minmax(100px, 1fr)); + } + + @media (min-width: 860px) { + grid-template-columns: repeat(4, minmax(100px, 1fr)); + } + + @media (min-width: 1200px) { + grid-template-columns: repeat(5, minmax(100px, 1fr)); + } +} diff --git a/src/components/grid/index.tsx b/src/components/grid/index.tsx new file mode 100644 index 00000000..bdcdb6a9 --- /dev/null +++ b/src/components/grid/index.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from "react" +import "./index.css" + +type GridProps = { + children: ReactNode + className?: string +} + +export const Grid = ({ children, className }: GridProps) => { + return
{children}
+} diff --git a/src/components/layout/index.css b/src/components/layout/index.css new file mode 100644 index 00000000..87ab0b89 --- /dev/null +++ b/src/components/layout/index.css @@ -0,0 +1,40 @@ +.layout{ + display: flex; + align-items: flex-start; +} + +.layout__sidebar-menu{ + display: flex; + flex-direction: column; + position: sticky; + top: 0px; + height: 100vh; + background-color: var(--light-colour); + flex-basis: max-content; + flex-shrink: 0; + z-index: 100; +} + +.layout__sidebar-menu-item{ + padding: 20px; + font-size: 1.5rem; + cursor: pointer; + -webkit-user-select: none; + user-select: none; + + &:hover{ + background-color: var(--hover-colour); + } +} + +.layout__sidebar-menu-item--active{ + background-color: var(--background-colour); +} + +.layout__sidebar-menu-item--disabled{ + cursor: unset; +} + +.layout__content { + flex-grow: 1; +} diff --git a/src/components/layout/index.tsx b/src/components/layout/index.tsx new file mode 100644 index 00000000..f45736af --- /dev/null +++ b/src/components/layout/index.tsx @@ -0,0 +1,53 @@ +import React, { Suspense, useState } from "react" +import { About } from "../about" +import { Cores } from "../cores" +import { Disconnections } from "../disconnections" +import { Games } from "../games" +import { Loader } from "../loader" +import { Saves } from "../saves" +import { Screenshots } from "../screenshots" +import { Settings } from "../settings" +import { ZipInstall } from "../zipInstall" +import "./index.css" + +export const Layout = () => { + const views = [ + "Pocket Sync", + "Games", + "Cores", + "Screenshots", + "Saves", + "Settings", + ] as const + const [viewName, setViewName] = useState("Pocket Sync") + + return ( +
+ + +
+ {views.map((v) => ( +
setViewName(v)} + > + {v} +
+ ))} +
+
+ }> + {viewName === "Screenshots" && } + {viewName === "Cores" && } + {viewName === "Pocket Sync" && } + {viewName === "Settings" && } + {viewName === "Games" && } + {viewName === "Saves" && } + +
+
+ ) +} diff --git a/src/components/link/index.css b/src/components/link/index.css new file mode 100644 index 00000000..a64ab90f --- /dev/null +++ b/src/components/link/index.css @@ -0,0 +1,9 @@ +.link{ + text-decoration: underline; + cursor: pointer; + display: inline-block; + + &:hover { + opacity: 0.8; + } +} diff --git a/src/components/link/index.tsx b/src/components/link/index.tsx new file mode 100644 index 00000000..109cb4a8 --- /dev/null +++ b/src/components/link/index.tsx @@ -0,0 +1,23 @@ +import { ReactNode } from "react" +import { open } from "@tauri-apps/api/shell" + +import "./index.css" + +type LinkProps = { + href?: string + className?: string + children: ReactNode +} + +export const Link = ({ children, className, href }: LinkProps) => { + return ( + { + if (href) open(window.encodeURI(href)) + }} + > + {children} + + ) +} diff --git a/src/components/loader/index.css b/src/components/loader/index.css new file mode 100644 index 00000000..7143ded3 --- /dev/null +++ b/src/components/loader/index.css @@ -0,0 +1,30 @@ +.loader { + height: 100%; + width: 100%; + background-color: #333; + display: flex; + align-items: center; + justify-content: center; +} + +.loader--full{ + height: 100vh; +} + +.loader::before{ + content: ""; + display: block; + border: 2px solid white; + border-radius: 50%; + border-left-color: transparent; + width: 25%; + aspect-ratio: 1 / 1; + + animation: spin 2s infinite linear; + will-change: transform; +} + +@keyframes spin { + from {transform:rotate(0deg);} + to {transform:rotate(360deg);} +} diff --git a/src/components/loader/index.tsx b/src/components/loader/index.tsx new file mode 100644 index 00000000..d8ad5378 --- /dev/null +++ b/src/components/loader/index.tsx @@ -0,0 +1,15 @@ +import React from "react" +import "./index.css" + +type LoaderProps = { + className?: string + fullHeight?: boolean + title?: string +} + +export const Loader = ({ className, fullHeight, title = "" }: LoaderProps) => ( +
+) diff --git a/src/components/modal/index.css b/src/components/modal/index.css new file mode 100644 index 00000000..e8e0224f --- /dev/null +++ b/src/components/modal/index.css @@ -0,0 +1,27 @@ +.modal__wrapper{ + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.8); + z-index: 1000; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.modal{ + width: calc(100vw - 100px); + height: calc(100vh - 100px); + background-color: var(--background-colour); + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: stretch; + box-sizing: border-box; + padding: 20px; + gap: 10px; +} diff --git a/src/components/modal/index.tsx b/src/components/modal/index.tsx new file mode 100644 index 00000000..2e40cbdd --- /dev/null +++ b/src/components/modal/index.tsx @@ -0,0 +1,16 @@ +import { ReactNode } from "react" + +import "./index.css" + +type ModalProps = { + children: ReactNode + className?: string +} + +export const Modal = ({ children, className }: ModalProps) => { + return ( +
+
{children}
+
+ ) +} diff --git a/src/components/progress/index.tsx b/src/components/progress/index.tsx new file mode 100644 index 00000000..ef528988 --- /dev/null +++ b/src/components/progress/index.tsx @@ -0,0 +1,14 @@ +import { Pocket } from "../three/pocket" +import { ProgressScreen } from "../three/progressScreen" + +type ProgressProps = { + value: number + max: number +} + +export const Progress = ({ value, max }: ProgressProps) => ( + } + /> +) diff --git a/src/components/saves/hooks/useBuildsaveZip.ts b/src/components/saves/hooks/useBuildsaveZip.ts new file mode 100644 index 00000000..aa3d3c2e --- /dev/null +++ b/src/components/saves/hooks/useBuildsaveZip.ts @@ -0,0 +1,18 @@ +import { useCallback } from "react" +import { useRecoilValue, useSetRecoilState } from "recoil" +import { fileSystemInvalidationAtom } from "../../../recoil/atoms" +import { AllSavesSelector } from "../../../recoil/selectors" +import { invokeBackupSaves } from "../../../utils/invokes" + +export const useBuildSaveZip = () => { + const allSaves = useRecoilValue(AllSavesSelector) + const invalidateFS = useSetRecoilState(fileSystemInvalidationAtom) + + return useCallback( + async (savePath: string, maxCount: number) => { + await invokeBackupSaves(allSaves, savePath, maxCount) + invalidateFS(Date.now()) + }, + [allSaves] + ) +} diff --git a/src/components/saves/index.css b/src/components/saves/index.css new file mode 100644 index 00000000..2774ae8d --- /dev/null +++ b/src/components/saves/index.css @@ -0,0 +1,129 @@ +.saves { + box-sizing: border-box; +} + +.saves__none{ + width: 100%; + height: calc(100vh - 60px); + font-size: 3rem; + + display: flex; + justify-content: center; + align-items: center; + + font-family: "Analogue"; + font-smooth: never; + -webkit-font-smoothing : none; + text-align: center; + line-height: 45px; +} + +.saves__list{ + padding: 20px; + overflow: auto; + + display: flex; + gap: 10px; + flex-direction: column; +} + +.saves__item{ + padding: 20px; + border-radius: 15px; + background-color: var(--info-colour); + + cursor: pointer; + + display: grid; + gap: 20px; + grid-template-columns: min-content 1fr min-content; + align-items: center; + justify-content: center; + grid-template-areas: + "a b c" + "a d c"; +} + +.saves__item--not-found{ + cursor: unset; +} + +.saves__item-path { + grid-area: b; + + word-break: break-all; +} + +.saves__info{ + grid-area: d; +} + +.saves__item-sync-button { + grid-area: a; + text-align: center; + + background-color: var(--green-colour); + padding: 10px; + aspect-ratio: 1 / 1; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + + &:hover{ + transform: scale(1.05); + } + +} + +.saves__item-restore-button { + grid-area: c; + padding: 10px; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + font-size: 1.25rem; + + &::after { + content: ""; + display: block; + width: 40px; + height: 40px; + + border-right: 2px solid white; + border-top: 2px solid white; + flex-grow: 0; + flex-shrink: 0; + transform: rotate(45deg); + } + + &:hover{ + transform: scale(1.1); + } +} + + +.saves__info-save-files{ + padding: 20px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.saves__info-save-file-versions { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.saves__info-save-file-version { + padding: 5px 10px; + background-color: var(--light-colour); + border-radius: 5px; + cursor: pointer; + + &:hover { + transform: scale(1.05); + } +} diff --git a/src/components/saves/index.tsx b/src/components/saves/index.tsx new file mode 100644 index 00000000..4a9c8103 --- /dev/null +++ b/src/components/saves/index.tsx @@ -0,0 +1,74 @@ +import { useCallback, useState } from "react" +import { useRecoilValue } from "recoil" +import { PocketSyncConfigSelector } from "../../recoil/selectors" +import { Controls } from "../controls" +import { useUpdateConfig } from "../settings/hooks/useUpdateConfig" +import { open } from "@tauri-apps/api/dialog" + +import "./index.css" +import { SavesItem } from "./item" +import { SaveInfo } from "./info" +import { Link } from "../link" +import { Tip } from "../tip" + +export const Saves = () => { + const [selectedSaveBackup, setSelectedSavebackup] = useState( + null + ) + + const updateConfig = useUpdateConfig() + const { saves } = useRecoilValue(PocketSyncConfigSelector) + const addBackupLocation = useCallback(async () => { + const directory = await open({ + directory: true, + }) + + if (!directory) return + + updateConfig("saves", [ + ...saves, + { + type: "zip", + backup_location: directory as string, + backup_count: 10, + }, + ]) + }, [saves]) + + if (selectedSaveBackup !== null) + return ( + setSelectedSavebackup(null)} + /> + ) + + return ( +
+ + + {saves.length === 0 && ( +
{"Add a backup location above"}
+ )} + {saves.length > 0 && ( +
+ {saves.map((s, index) => ( + setSelectedSavebackup(index)} + /> + ))} +
+ )} +
+ ) +} diff --git a/src/components/saves/info/index.tsx b/src/components/saves/info/index.tsx new file mode 100644 index 00000000..50bea592 --- /dev/null +++ b/src/components/saves/info/index.tsx @@ -0,0 +1,149 @@ +import { save } from "@tauri-apps/api/dialog" +import { useCallback, useMemo, useState } from "react" +import { useRecoilValue } from "recoil" +import { AllBackupZipsFilesSelectorFamily } from "../../../recoil/selectors" +import { SaveBackupPathTime } from "../../../types" +import { invokeRestoreZip } from "../../../utils/invokes" +import { Controls } from "../../controls" +import { Link } from "../../link" +import { Tip } from "../../tip" + +export const SaveInfo = ({ + backupPath, + onBack, +}: { + backupPath: string + onBack: () => void +}) => { + const [searchQuery, setSearchQuery] = useState("") + + const zipFilesInfo = useRecoilValue( + AllBackupZipsFilesSelectorFamily(backupPath) + ) + + const perSaveFormat = useMemo(() => { + const perSave: { + [filename: string]: { zip: SaveBackupPathTime; last_modified: number }[] + } = {} + + zipFilesInfo.forEach(({ zip, files }) => { + files + .filter((f) => f.filename.endsWith(".sav")) + .forEach(({ filename, last_modified }) => { + const existing = perSave[filename] + if (existing) { + if ( + !existing.find( + ({ last_modified: stored_last_modified }) => + last_modified === zip.last_modified + ) + ) { + existing.push({ zip, last_modified }) + } + } else { + perSave[filename] = [{ zip, last_modified }] + } + }) + }) + + return perSave + }, [zipFilesInfo]) + + const filteredSaves = useMemo( + () => + Object.fromEntries( + Object.entries(perSaveFormat).filter(([filename]) => + filename.toLowerCase().includes(searchQuery.toLowerCase()) + ) + ), + + [perSaveFormat, searchQuery] + ) + + return ( +
+ { + setSearchQuery(v) + }, + }, + ]} + > + + + {"This save backup system won't be as good as I'd like until "} + + {"this issue"} + + {" is fixed"} + + +
+ {Object.entries(filteredSaves).map(([savefile, versions]) => { + return ( + + ) + })} +
+
+ ) +} + +const SaveVersions = ({ + backupPath, + savefile, + versions, +}: { + backupPath: string + savefile: string + versions: { zip: SaveBackupPathTime; last_modified: number }[] +}) => { + const [isOpen, setIsOpen] = useState(true) + + const restore = useCallback( + async (zip: string) => { + const zipPath = `${backupPath}/${zip}` + await invokeRestoreZip(zipPath, savefile) + }, + [backupPath, savefile] + ) + + return ( +
+
setIsOpen((o) => !o)} + >{`${savefile} (${versions.length})`}
+ + {isOpen && ( +
+ {versions.map(({ zip }) => ( +
{ + restore(zip.filename) + }} + > + {new Date(zip.last_modified * 1000).toLocaleString()} +
+ ))} +
+ )} +
+ ) +} diff --git a/src/components/saves/item.tsx b/src/components/saves/item.tsx new file mode 100644 index 00000000..ab393a2c --- /dev/null +++ b/src/components/saves/item.tsx @@ -0,0 +1,55 @@ +import { useRecoilValue } from "recoil" +import { BackupZipsSelectorFamily } from "../../recoil/selectors" +import { SaveConfig } from "../../types" +import { useBuildSaveZip } from "./hooks/useBuildsaveZip" + +type SavesItemProps = { + config: SaveConfig + onClickRestore: () => void +} + +export const SavesItem = ({ config, onClickRestore }: SavesItemProps) => { + const saveZip = useBuildSaveZip() + + const { files, exists } = useRecoilValue( + BackupZipsSelectorFamily(config.backup_location) + ) + + if (!exists) { + return ( +
+
{config.backup_location}
+
{"Not found"}
+
+ ) + } + + return ( +
+
saveZip(config.backup_location, config.backup_count)} + > + {"Backup Now"} +
+
{config.backup_location}
+
+
{`Backups: ${files.length}`}
+ {files.length > 0 && ( + <> +
{`Last Backup: ${new Date( + (files.at(-1)?.last_modified || 0) * 1000 + ).toLocaleString()}`}
+
{`Oldest Backup: ${new Date( + (files.at(0)?.last_modified || 0) * 1000 + ).toLocaleString()}`}
+ + )} +
+ +
+ {"View Saves"} +
+
+ ) +} diff --git a/src/components/screenshots/hooks/useScreenshot.ts b/src/components/screenshots/hooks/useScreenshot.ts new file mode 100644 index 00000000..e2ac1b01 --- /dev/null +++ b/src/components/screenshots/hooks/useScreenshot.ts @@ -0,0 +1,67 @@ +import { useMemo, useState } from "react" +import { useRecoilValue } from "recoil" +import { SingleScreenshotSelectorFamily } from "../../../recoil/screenshots/selectors" +import { VideoJSONSelectorFamily } from "../../../recoil/screenshots/selectors" + +const POCKET_WIDTH = 1600 +const POCKET_HEIGHT = 1440 + +export const useScreenshot = ( + imageMode: "raw" | "upscaled", + fileName: string +) => { + const screenshot = useRecoilValue(SingleScreenshotSelectorFamily(fileName)) + if (screenshot === null) throw new Error(`Null file ${fileName}`) + + const videoJson = useRecoilValue( + VideoJSONSelectorFamily(`${screenshot.author}.${screenshot.core}`) + ) + + const image = useMemo(() => { + const image = new Image() + image.src = URL.createObjectURL(screenshot.file) + image.onload = () => setImageLoaded(true) + return image + }, [screenshot.file]) + + const [imageLoaded, setImageLoaded] = useState(false) + + const imageSrc = useMemo(() => { + switch (imageMode) { + case "raw": + return URL.createObjectURL(screenshot.file) + case "upscaled": + const canvas = document.createElement("canvas") + const context = canvas.getContext("2d") + + if (!context) throw new Error("Unable to get canvas context") + + const scalarMode = videoJson.video.scaler_modes.find( + ({ width, height }) => + width === image.width && height === image.height + ) + + if (scalarMode) { + if (scalarMode.aspect_h > scalarMode.aspect_w) { + canvas.height = POCKET_HEIGHT + canvas.width = + POCKET_HEIGHT * (scalarMode.aspect_w / scalarMode.aspect_h) + } else { + canvas.width = POCKET_WIDTH + canvas.height = + POCKET_WIDTH * (scalarMode.aspect_h / scalarMode.aspect_w) + } + } else { + canvas.height = image.height * 10 + canvas.width = image.width * 10 + } + + context.imageSmoothingEnabled = false + context?.drawImage(image, 0, 0, canvas.width, canvas.height) + + return canvas.toDataURL() + } + }, [imageMode, imageLoaded]) + + return imageSrc +} diff --git a/src/components/screenshots/index.css b/src/components/screenshots/index.css new file mode 100644 index 00000000..55f5acc4 --- /dev/null +++ b/src/components/screenshots/index.css @@ -0,0 +1,63 @@ +.screenshots--none{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; + font-size: 3rem; + padding: 20px; + box-sizing: border-box; + + font-family: "Analogue"; + font-smooth: never; + -webkit-font-smoothing : none; + text-align: center; + line-height: 45px; +} + + +.screenshots__item{ + overflow: hidden; + position: relative; + aspect-ratio: 160 / 144; + cursor: pointer; +} + +.screenshots__item-image{ + width: 100%; + height: 100%; + object-fit: contain; + + background-color: #111; + image-rendering: pixelated; +} + + +.screenshots__loading-item { + height: 190px !important; + aspect-ratio: 160 / 144; +} + +.screenshots__item-info{ + background-color: var(--info-colour); + padding: 5px; + font-size: 0.875rem; + position: absolute; + bottom: 0; + width: 100%; + + opacity: 0; + transform: translateY(80%); + transition: opacity 0.25s linear, transform 0.2s ease-out; +} + +.screenshots__item:hover .screenshots__item-info{ + opacity: 0.8; + transform: translateY(0); +} + +.screenshots__item-info-line{ + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} diff --git a/src/components/screenshots/index.tsx b/src/components/screenshots/index.tsx new file mode 100644 index 00000000..d648ac8e --- /dev/null +++ b/src/components/screenshots/index.tsx @@ -0,0 +1,60 @@ +import React, { Suspense, useMemo, useState } from "react" +import { useRecoilValue } from "recoil" +import { screenshotsListSelector } from "../../recoil/screenshots/selectors" +import { Screenshot } from "./item" + +import "./index.css" +import { Loader } from "../loader" +import { ScreenshotInfo } from "./info" +import { Grid } from "../grid" +import { useSaveScroll } from "../../hooks/useSaveScroll" + +export const Screenshots = () => { + const [selected, setSelected] = useState(null) + const screenshots = useRecoilValue(screenshotsListSelector) + + const { pushScroll, popScroll } = useSaveScroll() + + const sortedScreenshots = useMemo(() => { + return [...screenshots].sort((a, b) => b.localeCompare(a)) + }, [screenshots]) + + if (selected) { + return ( + { + setSelected(null) + popScroll() + }} + /> + ) + } + + if (sortedScreenshots.length === 0) { + return ( +
+

Once you take some screenshots they'll appear here

+
+ ) + } + + return ( + + {sortedScreenshots.map((fileName) => ( + } + key={fileName} + > + { + pushScroll() + setSelected(fileName) + }} + /> + + ))} + + ) +} diff --git a/src/components/screenshots/info.css b/src/components/screenshots/info.css new file mode 100644 index 00000000..f0948888 --- /dev/null +++ b/src/components/screenshots/info.css @@ -0,0 +1,60 @@ +.screenshot-info{ + height: 100vh; + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + overflow: hidden; +} + +.screenshot-info__controls{ + display: flex; + justify-content: space-between; + font-size: 1.125rem; + background-color: var(--info-colour); +} + +.screenshot-info__controls-item { + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + padding: 10px 20px; + accent-color: white; + + &:hover{ + background-color: var(--hover-colour); + } +} + +.screenshot-info__controls-item--back-button::before{ + content: ""; + display: block; + width: 10px; + height: 10px; + aspect-ratio: 1 / 1; + border: 1px solid white; + border-right-color: transparent; + border-bottom-color: transparent; + transform: rotate(-45deg); + margin-right: 5px; +} + +.screenshot-info__controls-checkbox{ + display: flex; + gap: 0.2em; + align-items: center; +} + +.screenshot-info__raw-image{ + flex-grow: 1; + flex-shrink: 1; + object-fit: contain; + image-rendering: pixelated; + height: 0; +} + +.screenshot-info__info{ + background-color: var(--info-colour); + padding: 10px; +} diff --git a/src/components/screenshots/info.tsx b/src/components/screenshots/info.tsx new file mode 100644 index 00000000..50e1b79d --- /dev/null +++ b/src/components/screenshots/info.tsx @@ -0,0 +1,118 @@ +import React, { useCallback, useMemo, useState } from "react" +import { useRecoilValue } from "recoil" +import { SingleScreenshotSelectorFamily } from "../../recoil/screenshots/selectors" +import { VideoJSONSelectorFamily } from "../../recoil/screenshots/selectors" +import "./info.css" + +import { useSaveFile } from "../../hooks/saveFile" +import { Controls } from "../controls" + +type ScreenshotInfo = { + fileName: string + onBack: () => void +} + +const POCKET_WIDTH = 1600 +const POCKET_HEIGHT = 1440 + +export const ScreenshotInfo = ({ fileName, onBack }: ScreenshotInfo) => { + const [imageMode, setImageMode] = useState<"raw" | "upscaled">("upscaled") + const screenshot = useRecoilValue(SingleScreenshotSelectorFamily(fileName)) + if (screenshot === null) throw new Error(`Null file ${fileName}`) + + const videoJson = useRecoilValue( + VideoJSONSelectorFamily(`${screenshot.author}.${screenshot.core}`) + ) + + const image = useMemo(() => { + const image = new Image() + image.src = URL.createObjectURL(screenshot.file) + image.onload = () => setImageLoaded(true) + return image + }, [screenshot.file]) + + const [imageLoaded, setImageLoaded] = useState(false) + + const imageSrc = useMemo(() => { + switch (imageMode) { + case "raw": + return URL.createObjectURL(screenshot.file) + case "upscaled": + const canvas = document.createElement("canvas") + const context = canvas.getContext("2d") + + if (!context) throw new Error("Unable to get canvas context") + + const scalarMode = videoJson.video.scaler_modes.find( + ({ width, height }) => + width === image.width && height === image.height + ) + + if (scalarMode) { + if (scalarMode.aspect_h > scalarMode.aspect_w) { + canvas.height = POCKET_HEIGHT + canvas.width = + POCKET_HEIGHT * (scalarMode.aspect_w / scalarMode.aspect_h) + } else { + canvas.width = POCKET_WIDTH + canvas.height = + POCKET_WIDTH * (scalarMode.aspect_h / scalarMode.aspect_w) + } + } else { + canvas.height = image.height * 10 + canvas.width = image.width * 10 + } + + context.imageSmoothingEnabled = false + context?.drawImage(image, 0, 0, canvas.width, canvas.height) + + return canvas.toDataURL() + } + }, [imageMode, imageLoaded]) + + const saveFile = useSaveFile() + + const openShareSheet = useCallback(async () => { + const file = await fetch(imageSrc) + .then((res) => res.arrayBuffer()) + .then( + (buf) => new File([buf], screenshot.file_name, { type: "image/png" }) + ) + + navigator.share({ files: [file] }) + }, [imageSrc]) + + return ( +
+ saveFile(screenshot.file_name, imageSrc), + }, + { type: "button", text: "Share", onClick: openShareSheet }, + { + type: "checkbox", + text: "Upscaled", + checked: imageMode === "upscaled", + onChange: (checked) => + checked ? setImageMode("upscaled") : setImageMode("raw"), + }, + ]} + /> + + +
+
{screenshot.game}
+
{screenshot.platform}
+
{screenshot.file_name}
+
+
+ ) +} diff --git a/src/components/screenshots/item.tsx b/src/components/screenshots/item.tsx new file mode 100644 index 00000000..dd61def3 --- /dev/null +++ b/src/components/screenshots/item.tsx @@ -0,0 +1,29 @@ +import React, { ReactElement, useCallback, useMemo } from "react" +import { useRecoilValue } from "recoil" +import { SingleScreenshotSelectorFamily } from "../../recoil/screenshots/selectors" + +type ScreenshotProps = { + fileName: string + onClick: () => void +} + +export const Screenshot = ({ + fileName, + onClick, +}: ScreenshotProps): ReactElement => { + const screenshot = useRecoilValue(SingleScreenshotSelectorFamily(fileName)) + if (screenshot === null) throw new Error(`Null file ${fileName}`) + + const blob = useMemo(() => URL.createObjectURL(screenshot.file), [screenshot]) + + return ( +
+ + +
+
{screenshot.game}
+
{screenshot.platform}
+
+
+ ) +} diff --git a/src/components/settings/hooks/useUpdateConfig.ts b/src/components/settings/hooks/useUpdateConfig.ts new file mode 100644 index 00000000..67f44399 --- /dev/null +++ b/src/components/settings/hooks/useUpdateConfig.ts @@ -0,0 +1,29 @@ +import { useCallback } from "react" +import { useRecoilValue, useSetRecoilState } from "recoil" +import { configInvalidationAtom, pocketPathAtom } from "../../../recoil/atoms" +import { PocketSyncConfigSelector } from "../../../recoil/selectors" +import { PocketSyncConfig } from "../../../types" +import { invokeSaveFile } from "../../../utils/invokes" + +export const useUpdateConfig = () => { + const currentConfig = useRecoilValue(PocketSyncConfigSelector) + const pocketPath = useRecoilValue(pocketPathAtom) + const invalidateConfigSelector = useSetRecoilState(configInvalidationAtom) + + return useCallback( + async ( + key: T, + value: PocketSyncConfig[T] + ) => { + const newConfig = { ...currentConfig, [key]: value } as PocketSyncConfig + const encoder = new TextEncoder() + await invokeSaveFile( + `${pocketPath}/pocket-sync.json`, + encoder.encode(JSON.stringify(newConfig, null, 2)) + ) + + setTimeout(() => invalidateConfigSelector(Date.now()), 500) + }, + [currentConfig] + ) +} diff --git a/src/components/settings/index.css b/src/components/settings/index.css new file mode 100644 index 00000000..89bd2193 --- /dev/null +++ b/src/components/settings/index.css @@ -0,0 +1,25 @@ +.settings{ + padding: 10px; +} + +.settings__items{ + padding: 20px; +} + +.settings__ramble{ + margin: 0; + padding: 0; + white-space: pre-wrap; +} + +.settings__row{ + & input, & select { + font-size: 1.4rem; + width: 80%; + } +} + +.settings__text-input-and-save{ + display: flex; + gap: 10px; +} diff --git a/src/components/settings/index.tsx b/src/components/settings/index.tsx new file mode 100644 index 00000000..9012a68b --- /dev/null +++ b/src/components/settings/index.tsx @@ -0,0 +1,55 @@ +import { useState } from "react" +import { useRecoilValue } from "recoil" +import { PocketSyncConfigSelector } from "../../recoil/selectors" +import { useUpdateConfig } from "./hooks/useUpdateConfig" + +import "./index.css" + +const ARCHIVE_URL_TEXT = `Please check with your local laws around the downloading of potentially copyrighted (arcade) ROM & BIOS files. +If you are comfortable with this, copy the following url into the input and hit "save".` + +export const Settings = () => { + const config = useRecoilValue(PocketSyncConfigSelector) + const [archiveUrlInput, setArchiveUrl] = useState(config.archive_url || "") + const updateConfig = useUpdateConfig() + + return ( +
+

{"Settings"}

+
+
+

{"Pocket Colour:"}

+ + +
+ +
+

{"ROM & BIOS archive:"}

+
{ARCHIVE_URL_TEXT}
+
{"https://archive.org/download/openFPGA-Files"}
+
+ setArchiveUrl(target.value)} + /> + +
+
+
+
+ ) +} diff --git a/src/components/three/index.css b/src/components/three/index.css new file mode 100644 index 00000000..fac38eb7 --- /dev/null +++ b/src/components/three/index.css @@ -0,0 +1,5 @@ +.three-pocket { + flex-shrink: 1; + flex-grow: 1; + flex-basis: 200px; +} diff --git a/src/components/three/pocket.tsx b/src/components/three/pocket.tsx new file mode 100644 index 00000000..cf86777c --- /dev/null +++ b/src/components/three/pocket.tsx @@ -0,0 +1,225 @@ +import { Canvas, useFrame } from "@react-three/fiber" +import { OrbitControls, Stats, RoundedBox } from "@react-three/drei" +import { ReactNode, useRef } from "react" +import { useRecoilValue, useSetRecoilState } from "recoil" +import { PocketModelColourAtom } from "../../recoil/atoms" + +import "./index.css" +import { PocketSyncConfigSelector } from "../../recoil/selectors" + +type PocketProps = { + move?: "none" | "spin" | "back-and-forth" + screenMaterial?: ReactNode +} + +const BLACK_COLOUR = "rgb(1,1,1)" +const WHITE_COLOUR = "rgb(90,90,90)" + +export const Pocket = ({ move = "none", screenMaterial }: PocketProps) => { + return ( + + + + + + + + + {/* */} + {/* */} + + ) +} + +const Body = ({ + move, + screenMaterial, +}: Pick) => { + const groupRef = useRef(null) + const speedRef = useRef(1) + useFrame((_, delta) => { + if (groupRef.current && speedRef.current) { + const speed = speedRef.current + switch (move) { + case "spin": + groupRef.current.rotateY(-0.6 * speed * delta) + break + case "back-and-forth": + groupRef.current.rotateY(-0.6 * speed * delta) + if (groupRef.current.rotation.y > 0.4) { + speedRef.current = 0.2 + } else if (groupRef.current.rotation.y < -0.4) { + speedRef.current = -0.2 + } + break + default: + break + } + } + }) + + return ( + + + + + + + + + + + + + + + + + + + + + ) +} + +const Screen = ({ screenMaterial }: PocketProps) => { + const { colour } = useRecoilValue(PocketSyncConfigSelector) + return ( + <> + {/* colour */} + + + + + + {/* LCD */} + + + {screenMaterial || ( + + )} + + {/* Glass */} + + + + + + ) +} + +const BUTTON_GAP = 1.25 as const + +const Buttons = () => { + const positions = [ + [BUTTON_GAP, 0, BUTTON_GAP], + [-BUTTON_GAP, 0, BUTTON_GAP], + [-BUTTON_GAP, 0, -BUTTON_GAP], + [BUTTON_GAP, 0, -BUTTON_GAP], + ] as const + + return ( + + {positions.map((p, index) => ( + + + + + ))} + + ) +} + +const BottomButtons = () => { + const positions = [ + [BUTTON_GAP, 0, BUTTON_GAP], + [0, 0, 0], + [-BUTTON_GAP, 0, -BUTTON_GAP], + ] as const + + return ( + + {positions.map((p, index) => ( + + + + + ))} + + ) +} + +const DPAD = () => { + const args = [ + [BUTTON_GAP, 1, BUTTON_GAP * 3.5], + [BUTTON_GAP * 3.5, 1, BUTTON_GAP], + ] as const + + return ( + + {args.map((a, index) => ( + + {/* @ts-ignore */} + + + + ))} + + ) +} + +const Material = ({ isButton = false }: { isButton?: boolean }) => { + const { colour } = useRecoilValue(PocketSyncConfigSelector) + return ( + + ) +} diff --git a/src/components/three/progressScreen.tsx b/src/components/three/progressScreen.tsx new file mode 100644 index 00000000..646ce7e4 --- /dev/null +++ b/src/components/three/progressScreen.tsx @@ -0,0 +1,66 @@ +import React, { useEffect, useState } from "react" +import { NearestFilter, Texture } from "three" + +type ProgressScreenProps = { + value: number + max: number +} + +const SCALE = 4 + +const DARKEST_GREEN = "#0f380f" +const DARK_GREEN = "#306230" +const LIGHT_GREEN = "#8bac0f" +const LIGHTEST_GREEN = "#9bbc0f" + +export const ProgressScreen = ({ + value = 33, + max = 100, +}: ProgressScreenProps) => { + const [texture, setTexture] = useState(null) + + useEffect(() => { + const canvas = document.createElement("canvas") + canvas.width = 160 * SCALE + canvas.height = 140 * SCALE + + const context = canvas.getContext("2d") + if (!context) return + + context.fillStyle = DARKEST_GREEN + context.fillRect(0, 0, canvas.width, canvas.height) + + context.fillStyle = DARK_GREEN + console.log({ value, max }) + context.fillRect(0, 0, canvas.width * (value / max), canvas.height) + + context.fillStyle = LIGHTEST_GREEN + context.font = `${85 * SCALE}px Analogue` + const text = `${((value / max) * 100).toFixed(0)}%` + context.textAlign = "center" + context.textBaseline = "middle" + context.fillText(text, canvas.width / 2, canvas.height / 2) + + canvas.toBlob((b) => { + if (!b) return + const image = new Image() + image.src = URL.createObjectURL(b) + image.onload = () => { + const newTexture = new Texture() + newTexture.image = image + newTexture.needsUpdate = true + newTexture.anisotropy = 4 + newTexture.minFilter = NearestFilter + newTexture.magFilter = NearestFilter + setTexture(newTexture) + } + }) + }, [value, max]) + + return ( + + ) +} diff --git a/src/components/three/randomScreenshotScreen.tsx b/src/components/three/randomScreenshotScreen.tsx new file mode 100644 index 00000000..9ff1456a --- /dev/null +++ b/src/components/three/randomScreenshotScreen.tsx @@ -0,0 +1,76 @@ +import React, { useEffect, useMemo, useRef, useState } from "react" +import { useRecoilCallback, useRecoilValue } from "recoil" +import { + screenshotsListSelector, + SingleScreenshotSelectorFamily, +} from "../../recoil/screenshots/selectors" +import { Texture } from "three" + +type RandomScreenshotScreenProps = { + interval?: number +} + +export const RandomScreenshotScreen = ({ + interval = 2000, +}: RandomScreenshotScreenProps) => { + const screenshotList = useRecoilValue(screenshotsListSelector) + const [randomNudge, setRandomNudge] = useState(0) + + const screenshotName = useMemo(() => { + return screenshotList[Math.floor(Math.random() * screenshotList.length)] + }, [screenshotList, randomNudge]) + + useEffect(() => { + const changeImageInterval = setInterval( + () => setRandomNudge(Date.now()), + interval + ) + + return () => { + clearInterval(changeImageInterval) + } + }) + + if (screenshotList.length === 0) + return + + return +} + +const ScreenshotScreen = ({ name }: { name: string }) => { + const [texture, setTexture] = useState(null) + + const loadImageFile = useRecoilCallback( + ({ snapshot }) => + async (imageName: string) => { + const screenshot = await snapshot.getPromise( + SingleScreenshotSelectorFamily(imageName) + ) + if (!screenshot) return + const image = new Image() + image.src = URL.createObjectURL(screenshot.file) + return image + } + ) + + useEffect(() => { + ;(async () => { + const image = await loadImageFile(name) + if (!image) return + image.onload = () => { + const newTexture = new Texture() + newTexture.image = image + newTexture.needsUpdate = true + newTexture.anisotropy = 4 + setTexture(newTexture) + } + })() + }, [name]) + + return ( + + ) +} diff --git a/src/components/tip/index.css b/src/components/tip/index.css new file mode 100644 index 00000000..6f85ba36 --- /dev/null +++ b/src/components/tip/index.css @@ -0,0 +1,23 @@ +.tip{ + width: 100%; + text-align: center; + box-sizing: border-box; + padding: 20px 10px; + justify-content: center; + align-items: center; + + + &::before { + content: "i"; + display: inline-flex; + justify-content: center; + align-items: center; + margin-right: 10px; + border-radius: 50%; + + aspect-ratio: 1 / 1; + border: 1px solid white; + width: 1.1em; + height: 1.1em; + } +} diff --git a/src/components/tip/index.tsx b/src/components/tip/index.tsx new file mode 100644 index 00000000..da61d656 --- /dev/null +++ b/src/components/tip/index.tsx @@ -0,0 +1,6 @@ +import { ReactNode } from "react" +import "./index.css" + +export const Tip = ({ children }: { children: ReactNode }) => ( +
{children}
+) diff --git a/src/components/zipInstall/hooks.ts b/src/components/zipInstall/hooks.ts new file mode 100644 index 00000000..f1b09400 --- /dev/null +++ b/src/components/zipInstall/hooks.ts @@ -0,0 +1,117 @@ +import { emit, listen } from "@tauri-apps/api/event" +import { useCallback, useEffect, useMemo, useState } from "react" +import { useSetRecoilState } from "recoil" +import { fileSystemInvalidationAtom } from "../../recoil/atoms" +import { FileTreeNode, InstallZipEventPayload } from "./types" + +export const useListenForZipInstall = () => { + const [installState, setInstallState] = + useState(null) + + const updateFSInvalidationAtom = useSetRecoilState(fileSystemInvalidationAtom) + + useEffect(() => { + const unlisten = listen( + "install-zip-event", + ({ payload }) => setInstallState(payload) + ) + return () => { + unlisten.then((l) => l()) + } + }, [setInstallState]) + + useEffect(() => { + const unlisten = listen<{ error?: string }>( + "install-zip-finished", + ({ payload }) => { + setInstallState(null) + updateFSInvalidationAtom(Date.now()) + } + ) + return () => { + unlisten.then((l) => l()) + } + }, [setInstallState]) + + return { installState } +} + +export const useTree = (files: InstallZipEventPayload["files"]) => { + return useMemo(() => { + if (!files) return null + + const sortedFiles = [...files].sort(({ path: pathA }, { path: pathB }) => + pathA.localeCompare(pathB) + ) + + return sortedFiles.reduce((prev, curr) => { + const newTree: FileTreeNode[] = [...prev] + const fileBits = curr.path.split("/") + let treeNode = newTree + + for (let index = 0; index < fileBits.length; index++) { + const element = fileBits[index] + if (element === "") continue + if (!treeNode.find(({ name }) => name === element)) { + treeNode.push({ + name: element, + full: curr.path, + exists: curr.exists, + is_dir: index !== fileBits.length - 1, + children: [], + }) + } + + treeNode = treeNode.find(({ name }) => name === element)?.children || [] + } + + return newTree + }, [] as FileTreeNode[]) + }, [files]) +} + +export const useAllowedFiles = (files: InstallZipEventPayload["files"]) => { + const [allowedFiles, setAllowedFiles] = useState(null) + + useEffect(() => { + setAllowedFiles((f) => { + if (f === null && files) return files.map(({ path }) => path) + return f + }) + }, [files]) + + const toggleFile = useCallback( + (path: string) => { + setAllowedFiles((f) => { + if (!f) return f + + if (f.includes(path)) { + return f.filter((p) => p !== path) + } else { + return [...f, path] + } + }) + }, + [setAllowedFiles] + ) + + return { allowedFiles, toggleFile } +} + +export const useZipInstallButtons = (allowedFiles: string[] | null) => { + const confirm = useCallback(() => { + emit("install-confirmation", { + paths: allowedFiles, + allow: true, + }) + }, [allowedFiles]) + + const cancel = useCallback(() => { + emit("install-confirmation", { + paths: [], + allow: false, + }) + }, []) + + return { confirm, cancel } +} diff --git a/src/components/zipInstall/index.css b/src/components/zipInstall/index.css new file mode 100644 index 00000000..e1dcb8c4 --- /dev/null +++ b/src/components/zipInstall/index.css @@ -0,0 +1,49 @@ +.zip-install__paths{ + flex-grow: 1; + overflow: auto; + background-color: var(--info-colour); + border-radius: 10px; + box-sizing: border-box; + padding: 10px; +} + +.zip-install__controls { + display: flex; + justify-content: space-around; +} + +.zip-install__tree-node{ + margin-left: 20px; + display: flex; + flex-direction: column; +} + +.zip-install__tree-node-info{ + display: flex; + gap: 5px; + align-items: center; +} + +.zip-install__progress{ + width: 100%; + accent-color: unset; +} + +.zip-install__tree-node-name{ + display: flex; + gap: inherit; + cursor: pointer; + align-items: center; +} + +.zip-install__tree-arrow{ + display: inline-block; + width: 12px; + height: 12px; + background-color: white; + clip-path: polygon(0% 0%, 50% 100%, 100% 0%); +} + +.zip-install__tree-arrow--collapsed { + transform: rotate(-90deg); +} diff --git a/src/components/zipInstall/index.tsx b/src/components/zipInstall/index.tsx new file mode 100644 index 00000000..05db977e --- /dev/null +++ b/src/components/zipInstall/index.tsx @@ -0,0 +1,62 @@ +import { Modal } from "../modal" +import { + useAllowedFiles, + useListenForZipInstall, + useTree, + useZipInstallButtons, +} from "./hooks" +import { TreeNode } from "./treeNode" +import { InstallZipEventPayload } from "./types" +import { Progress } from "../progress" +import "./index.css" + +export const ZipInstall = () => { + const { installState } = useListenForZipInstall() + + if (!installState) return null + return +} + +export const ZipInstallInner = ({ + files, + progress, + title, +}: InstallZipEventPayload) => { + const tree = useTree(files) + const { allowedFiles, toggleFile } = useAllowedFiles(files) + const { confirm, cancel } = useZipInstallButtons(allowedFiles) + + if (progress) { + return ( + +

{title}

+ +
+ ) + } + + return ( + +

{title}

+
+ {!tree &&

{`Scanning files...`}

} + {tree && + allowedFiles && + tree.map((node) => ( + + ))} +
+ +
+ + +
+
+ ) +} diff --git a/src/components/zipInstall/treeNode.tsx b/src/components/zipInstall/treeNode.tsx new file mode 100644 index 00000000..38e19fd6 --- /dev/null +++ b/src/components/zipInstall/treeNode.tsx @@ -0,0 +1,54 @@ +import { useState } from "react" +import { FileTreeNode } from "./types" + +export const TreeNode = ({ + node, + allowed, + defaultExpanded = false, + toggleFile, +}: { + node: FileTreeNode + defaultExpanded?: boolean + allowed: string[] + toggleFile: (path: string) => void +}) => { + const [expanded, setExpanded] = useState(defaultExpanded) + + return ( +
+
+ {!node.is_dir && ( + toggleFile(node.full)} + > + )} +
setExpanded((e) => !e)} + > + {node.is_dir && ( +
+ )} + {node.name} + {node.is_dir ? "/" : ""} +
+
+ + {expanded && + node.children.map((n) => ( + + ))} +
+ ) +} diff --git a/src/components/zipInstall/types.ts b/src/components/zipInstall/types.ts new file mode 100644 index 00000000..91d48aef --- /dev/null +++ b/src/components/zipInstall/types.ts @@ -0,0 +1,13 @@ +export type FileTreeNode = { + name: string + full: string + exists: boolean + is_dir: boolean + children: FileTreeNode[] +} + +export type InstallZipEventPayload = { + title: string + files?: { path: string; exists: boolean }[] + progress?: { value: number; max: number } +} diff --git a/src/config_file.rs b/src/config_file.rs deleted file mode 100644 index 51e4e59a..00000000 --- a/src/config_file.rs +++ /dev/null @@ -1,38 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::{fs, io::ErrorKind, path::PathBuf}; - -#[derive(Serialize, Deserialize, Debug)] -pub struct PocketSyncConfig { - pub last_run_timestamp: i64, -} - -impl PocketSyncConfig { - pub fn read(pocket_path: &PathBuf) -> PocketSyncConfig { - let json_path = pocket_path.join("pocket_sync.json"); - if let Ok(data) = fs::read_to_string(&json_path).or_else(|err| match err.kind() { - ErrorKind::NotFound => { - let default_struct = PocketSyncConfig { - last_run_timestamp: 0, - }; - - default_struct.write(pocket_path); - let json = serde_json::to_string(&default_struct); - json - } - _ => panic!("Error trying to read config {}", err), - }) { - if let Ok(result) = serde_json::from_str(&data) { - return result; - } - } - - panic!("Failed to read or create pocket_sync.json") - } - - pub fn write(&self, pocket_path: &PathBuf) -> () { - let json_path = pocket_path.join("pocket_sync.json"); - if let Ok(json) = serde_json::to_string(&self) { - fs::write(&json_path, &json).expect("Failed to write pocket_sync.json"); - } - } -} diff --git a/src/cores.rs b/src/cores.rs deleted file mode 100644 index 6cc088d0..00000000 --- a/src/cores.rs +++ /dev/null @@ -1,160 +0,0 @@ -#[derive(Debug, PartialEq)] -pub enum SupportedCore { - GB, - GBC, - GBA, - TGFX16, - NES, - SNES, - GameGear, - MasterSystem, - Genesis, - NEOGEO, - Arduboy, - SuperVision, -} - -pub trait TransformCore { - fn to_pocket(&self) -> String; - fn to_mister(&self) -> String; - - fn from_pocket(name: &str) -> Option; - fn from_mister(name: &str) -> Option; - - fn pocket_folder(&self) -> String; - - fn rom_filetypes(&self) -> Vec; -} - -impl TransformCore for SupportedCore { - fn to_pocket(&self) -> String { - String::from(match self { - SupportedCore::Arduboy => "arduboy", - SupportedCore::GameGear => "gg", - SupportedCore::GB => "gb", - SupportedCore::GBA => "gba", - SupportedCore::GBC => "gbc", - SupportedCore::Genesis => "genesis", - SupportedCore::MasterSystem => "sms", - SupportedCore::NEOGEO => "ng", - SupportedCore::NES => "nes", - SupportedCore::SNES => "snes", - SupportedCore::SuperVision => "supervision", - SupportedCore::TGFX16 => "pce", - }) - } - - fn to_mister(&self) -> String { - String::from(match self { - SupportedCore::Arduboy => "Arduboy", - SupportedCore::GameGear => "SMS", - SupportedCore::GB => "GAMEBOY", - SupportedCore::GBA => "GBA", - SupportedCore::GBC => "GAMEBOY", - SupportedCore::Genesis => "Genesis", - SupportedCore::MasterSystem => "SMS", - SupportedCore::NEOGEO => "NEOGEO", - SupportedCore::NES => "NES", - SupportedCore::SNES => "SNES", - SupportedCore::SuperVision => "SuperVision", - SupportedCore::TGFX16 => "TGFX16", - }) - } - - fn from_pocket(name: &str) -> Option { - match name { - "arduboy" => Some(SupportedCore::Arduboy), - "gb" => Some(SupportedCore::GB), - "gba" => Some(SupportedCore::GBA), - "gbc" => Some(SupportedCore::GBC), - "genesis" => Some(SupportedCore::Genesis), - "gg" => Some(SupportedCore::GameGear), - "nes" => Some(SupportedCore::NES), - "ng" => Some(SupportedCore::NEOGEO), - "pce" => Some(SupportedCore::TGFX16), - "sms" => Some(SupportedCore::MasterSystem), - "snes" => Some(SupportedCore::SNES), - "supervision" => Some(SupportedCore::SuperVision), - _ => None, - } - } - - fn from_mister(name: &str) -> Option { - // Some cores on the MiSTer do double duty (GAMEBOY, SMS) will need to work out - // How to deal with that (save file header? try to find the full rom name?) - match name { - "Arduboy" => Some(SupportedCore::Arduboy), - "NES" => Some(SupportedCore::NES), - "SNES" => Some(SupportedCore::SNES), - "GAMEBOY" => Some(SupportedCore::GBC), - "GBA" => Some(SupportedCore::GBA), - "SMS" => Some(SupportedCore::MasterSystem), - "TGFX16" => Some(SupportedCore::TGFX16), - "NEOGEO" => Some(SupportedCore::NEOGEO), - "Genesis" => Some(SupportedCore::Genesis), - "SuperVision" => Some(SupportedCore::SuperVision), - _ => None, - } - } - - fn pocket_folder(&self) -> String { - String::from(match self { - Self::NEOGEO => "Mazamars312.NeoGeo", - _ => "common", - }) - } - - fn rom_filetypes(&self) -> Vec { - (match self { - SupportedCore::Arduboy => vec!["hex"], - SupportedCore::GameGear => vec!["gg"], - SupportedCore::GB => vec!["gb"], - SupportedCore::GBA => vec!["gba"], - SupportedCore::GBC => vec!["gbc"], - SupportedCore::Genesis => vec!["md", "bin", "gen", "smd"], - SupportedCore::MasterSystem => vec!["sms"], - SupportedCore::NEOGEO => vec!["json"], - SupportedCore::NES => vec!["nes"], - SupportedCore::SNES => vec!["smc", "sfc"], - SupportedCore::SuperVision => vec!["sv", "bin"], - SupportedCore::TGFX16 => vec!["pce"], - _ => vec![], - }) - .iter() - .map(|s| s.to_string()) - .collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn self_compare() { - let mister_core_a = SupportedCore::from_mister("SNES").unwrap(); - let mister_core_b = SupportedCore::from_mister("SNES").unwrap(); - assert_eq!(mister_core_a, mister_core_b); - - let mister_core_a = SupportedCore::from_mister("NES").unwrap(); - assert_ne!(mister_core_a, mister_core_b); - } - - #[test] - fn things_that_should_match() { - let mister_core = SupportedCore::from_mister("SNES").unwrap(); - let pocket_core = SupportedCore::from_pocket("snes").unwrap(); - assert_eq!(mister_core, pocket_core); - - let mister_core = SupportedCore::from_mister("GAMEBOY").unwrap(); - let pocket_core = SupportedCore::from_pocket("gbc").unwrap(); - assert_eq!(pocket_core.to_mister(), mister_core.to_mister()); - } - - #[test] - fn things_that_should_return_none() { - let mister_core = SupportedCore::from_mister("PSX"); - let pocket_core = SupportedCore::from_pocket("galaga"); - assert_eq!(mister_core, None); - assert_eq!(pocket_core, None); - } -} diff --git a/src/font.css b/src/font.css new file mode 100644 index 00000000..e05526a0 --- /dev/null +++ b/src/font.css @@ -0,0 +1,7 @@ +@font-face { + font-family: 'Analogue'; + src: url('assets/AnalogueOS-Regular.woff2') format('woff2'), + url('assets/AnalogueOS-Regular.woff') format('woff'); + font-weight: normal; + font-style: normal; +} diff --git a/src/hooks/saveFile.ts b/src/hooks/saveFile.ts new file mode 100644 index 00000000..2910072a --- /dev/null +++ b/src/hooks/saveFile.ts @@ -0,0 +1,33 @@ +import { save } from "@tauri-apps/api/dialog" +import { useCallback } from "react" +import { invokeSaveFile } from "../utils/invokes" + +export const useSaveFile = () => { + const onSaveFile = useCallback(async (name: string, file: File | string) => { + const filePath = await save({ + title: "Save screenshot", + filters: [ + { + name: "image", + extensions: ["png"], + }, + ], + defaultPath: name, + }) + + if (!filePath) return + + const buffer = await fileToBuffer(file) + await invokeSaveFile(filePath, new Uint8Array(buffer)) + }, []) + + return onSaveFile +} + +const fileToBuffer = async (file: File | string) => { + if (typeof file === "string") { + return fetch(file).then((res) => res.arrayBuffer()) + } else { + return file.arrayBuffer() + } +} diff --git a/src/hooks/useCategoryLookup.ts b/src/hooks/useCategoryLookup.ts new file mode 100644 index 00000000..574d21f7 --- /dev/null +++ b/src/hooks/useCategoryLookup.ts @@ -0,0 +1,18 @@ +import { useRecoilCallback } from "recoil" +import { CoreInventorySelector } from "../recoil/inventory/selectors" + +export const useCategoryLookup = () => { + // might change this to query the filesystem instead but that'll + // probably take _a while_ to load + return useRecoilCallback(({ snapshot }) => (coreName: string) => { + const coreInventory = snapshot.getLoadable(CoreInventorySelector) + + if (coreInventory.state !== "hasValue") return "Unknown" + const { data } = coreInventory.getValue() + const inventoryItem = data.find(({ identifier }) => identifier === coreName) + const aRelease = inventoryItem?.release || inventoryItem?.prerelease + if (!aRelease) return "Unknown" + + return aRelease.platform.category ?? "Uncategorized" + }) +} diff --git a/src/hooks/useInstallCore.ts b/src/hooks/useInstallCore.ts new file mode 100644 index 00000000..3a99ecdb --- /dev/null +++ b/src/hooks/useInstallCore.ts @@ -0,0 +1,13 @@ +import { useCallback } from "react" +import { emit } from "@tauri-apps/api/event" + +export const useInstallCore = () => { + const installCore = useCallback(async (coreName: string, zipUrl: string) => { + emit("install-core", { + core_name: coreName, + zip_url: zipUrl, + }) + }, []) + + return { installCore } +} diff --git a/src/hooks/useInstallRequiredFiles.ts b/src/hooks/useInstallRequiredFiles.ts new file mode 100644 index 00000000..e8c7f23f --- /dev/null +++ b/src/hooks/useInstallRequiredFiles.ts @@ -0,0 +1,49 @@ +import { invoke } from "@tauri-apps/api" +import { listen } from "@tauri-apps/api/event" +import { useCallback, useEffect, useState } from "react" +import { useRecoilValue, useSetRecoilState } from "recoil" +import { fileSystemInvalidationAtom } from "../recoil/atoms" +import { PocketSyncConfigSelector } from "../recoil/selectors" +import { RequiredFileInfo } from "../types" + +export const useInstallRequiredFiles = (closeModal: () => void) => { + const { archive_url } = useRecoilValue(PocketSyncConfigSelector) + const invalidateFS = useSetRecoilState(fileSystemInvalidationAtom) + + const [progress, setProgress] = useState<{ + value: number + max: number + } | null>(null) + + useEffect(() => { + const unlisten = listen<{ max: number; value: number }>( + "file-progress", + ({ payload }) => { + setProgress(payload) + if (payload.max === payload.value) { + invalidateFS(Date.now()) + closeModal() + } + } + ) + + return () => { + unlisten.then((l) => l()) + } + }, []) + + const installRequiredFiles = useCallback( + async (files: RequiredFileInfo[]) => { + if (!archive_url) + throw new Error("Attempt to download without an `archive_url` set") + + const response = await invoke("install_archive_files", { + files, + archiveUrl: archive_url, + }) + }, + [archive_url] + ) + + return { installRequiredFiles, progress } +} diff --git a/src/hooks/useInventoryItem.ts b/src/hooks/useInventoryItem.ts new file mode 100644 index 00000000..bef57313 --- /dev/null +++ b/src/hooks/useInventoryItem.ts @@ -0,0 +1,12 @@ +import { useRecoilValue } from "recoil" +import { CoreInventorySelector } from "../recoil/inventory/selectors" + +export const useInventoryItem = (coreName: string) => { + const coreInventory = useRecoilValue(CoreInventorySelector) + const inventoryItem = coreInventory.data.find( + ({ identifier }) => identifier === coreName + ) + + if (!inventoryItem) return null + return inventoryItem +} diff --git a/src/hooks/useSaveScroll.ts b/src/hooks/useSaveScroll.ts new file mode 100644 index 00000000..be6bbeb2 --- /dev/null +++ b/src/hooks/useSaveScroll.ts @@ -0,0 +1,19 @@ +import { useCallback, useState } from "react" + +export const useSaveScroll = () => { + const [savedScroll, setSavedScroll] = useState(null) + + const pushScroll = useCallback(() => { + setSavedScroll(window.pageYOffset) + window.scrollTo({ top: 0 }) + }, []) + + const popScroll = useCallback(() => { + requestAnimationFrame(() => { + if (savedScroll) window.scrollTo({ top: savedScroll }) + setSavedScroll(null) + }) + }, [savedScroll]) + + return { pushScroll, popScroll } +} diff --git a/src/hooks/useUninstallCore.ts b/src/hooks/useUninstallCore.ts new file mode 100644 index 00000000..8d32ee11 --- /dev/null +++ b/src/hooks/useUninstallCore.ts @@ -0,0 +1,25 @@ +import { useCallback } from "react" +import { useSetRecoilState } from "recoil" +import { fileSystemInvalidationAtom } from "../recoil/atoms" +import { ask } from "@tauri-apps/api/dialog" +import { invokeUninstallCore } from "../utils/invokes" + +export const useUninstallCore = () => { + const updateFSInvalidationAtom = useSetRecoilState(fileSystemInvalidationAtom) + + return useCallback(async (coreName: string) => { + const sure = await ask( + "This will remove the core, but not any games, saves, library data, or platform information. Are you sure?", + { title: "Uninstall Core", type: "warning" } + ) + + if (!sure) return + + const success = await invokeUninstallCore(coreName) + + if (success) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + updateFSInvalidationAtom(Date.now()) + } + }, []) +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 87f40d43..00000000 --- a/src/main.rs +++ /dev/null @@ -1,248 +0,0 @@ -mod config_file; -mod cores; -mod mister_ftp; -mod pocket_files; -mod save_compare; -mod user_input; - -use chrono::TimeZone; -use clap::Parser; -use cores::{SupportedCore, TransformCore}; -use std::{ - fmt, fs, - path::{Path, PathBuf}, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; -use walkdir::{DirEntry, WalkDir}; - -use crate::{ - config_file::PocketSyncConfig, - mister_ftp::logged_in_ftp, - user_input::{report_status, UserInput}, -}; -use crate::{ - save_compare::{remove_duplicates, SaveComparison}, - user_input::choose_save, -}; - -#[derive(Debug, PartialEq)] -pub struct SaveInfo { - pub game: String, - pub path: PathBuf, - pub date_modified: i64, - pub core: SupportedCore, -} - -impl fmt::Display for SaveInfo { - // This trait requires `fmt` with this exact signature. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let time = chrono::Local.timestamp(self.date_modified.try_into().unwrap(), 0); - write!( - f, - "Name: {}\nLast Modified: {}\nCore: {}", - self.game, - time, - self.core.to_pocket() - ) - } -} - -#[derive(Debug)] -pub enum PlatformSave { - PocketSave(SaveInfo), - MiSTerSave(SaveInfo), -} - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - path: PathBuf, - #[arg(long)] - host_mister: String, - #[arg(long, default_value = "root")] - user_mister: String, - #[arg(long, default_value = "1")] - password_mister: String, -} - -fn main() { - let args = Args::parse(); - let mut config = PocketSyncConfig::read(&args.path); - - if let Ok(pocket_saves) = find_pocket_saves(&args.path) { - if let Ok(mister_saves) = - find_mister_saves(&args.host_mister, &args.user_mister, &args.password_mister) - { - let mut save_comparisons: Vec = Vec::new(); - - for pocket_save in &pocket_saves { - save_comparisons.push(save_compare::check_save( - &pocket_save, - &pocket_saves, - &mister_saves, - config.last_run_timestamp, - )) - } - - for mister_save in &mister_saves { - save_comparisons.push(save_compare::check_save( - &mister_save, - &pocket_saves, - &mister_saves, - config.last_run_timestamp, - )) - } - - let save_comparisons = remove_duplicates(save_comparisons); - let user_choice = report_status(&save_comparisons); - - match user_choice { - UserInput::Cancel => { - println!("Ok, exiting!"); - std::process::exit(0); - } - _ => {} - } - - for save_comp in save_comparisons { - let choice = match &save_comp { - SaveComparison::Conflict(save_pair) => choose_save(&save_pair), - SaveComparison::MiSTerNewer(_) | SaveComparison::MiSTerOnly(_) => { - UserInput::UseMister - } - SaveComparison::PocketNewer(_) | SaveComparison::PocketOnly(_) => { - UserInput::UsePocket - } - SaveComparison::NoSyncNeeded => UserInput::Skip, - }; - - if choice == UserInput::Skip { - continue; - } - - if let Ok(mut ftp_stream) = - logged_in_ftp(&args.host_mister, &args.user_mister, &args.password_mister) - { - match choice { - UserInput::UseMister => { - save_comp - .use_mister(&mut ftp_stream, &args.path) - .expect("Failed to copy save from MiSTer"); - } - UserInput::UsePocket => { - save_comp - .use_pocket(&mut ftp_stream, &args.path) - .expect("Failed to copy save from Pocket"); - } - _ => {} - } - } - } - - let start = SystemTime::now(); - config.last_run_timestamp = start - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_secs() as i64; - - // Push a little bit into the future so an immediate re-run finds nothing - config.last_run_timestamp += 60; - config.write(&args.path); - - println!("All done!"); - std::process::exit(0); - } else { - println!("Failed to get MiSTer saves"); - std::process::exit(1); - } - } else { - println!("Failed to get Pocket saves"); - std::process::exit(1); - } -} - -fn find_pocket_saves(path: &PathBuf) -> Result, String> { - println!("Scanning Pocket files"); - let mut saves: Vec = Vec::new(); - let saves_path = Path::new(path).join("Saves"); - - for entry in WalkDir::new(saves_path).into_iter().filter_map(|e| e.ok()) { - if !entry.file_type().is_file() { - continue; - } - - if let Some(extension) = entry.path().extension() { - if extension == "sav" { - if let Ok(time) = fs::metadata(entry.path()).and_then(|md| md.modified()) { - if let Some(core) = SupportedCore::from_pocket(&get_pocket_system_name(&entry)) - { - saves.push(PlatformSave::PocketSave(SaveInfo { - game: String::from(entry.file_name().to_str().unwrap_or("unknown")), - path: PathBuf::from(entry.path()), - date_modified: time - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or(Duration::from_secs(0)) - .as_secs() as i64, - core, - })) - } - } - } - } - } - - return Ok(saves); -} - -fn get_pocket_system_name(entry: &DirEntry) -> String { - let mut current = entry.path(); - - while let Some(parent) = current.parent() { - if parent.ends_with("Saves") { - return String::from( - current - .file_stem() - .and_then(|s| s.to_str()) - .unwrap_or("unknown"), - ); - } - - current = parent; - } - - return String::from("unknown"); -} - -fn find_mister_saves( - host: &str, - user: &str, - password: &str, -) -> Result, suppaftp::FtpError> { - println!("Connecting to MiSTer"); - let mut ftp_stream = logged_in_ftp(host, user, password)?; - let mut saves: Vec = Vec::new(); - let _ = ftp_stream.cwd("/media/fat/saves")?; - let systems = ftp_stream.nlst(None)?; - - for system in systems { - print!("."); - let _ = ftp_stream.cwd(&system)?; - let system_saves = ftp_stream.nlst(None)?; - for system_save in system_saves { - let modtime = ftp_stream.mdtm(&system_save)?; - if let Some(core) = SupportedCore::from_mister(&system) { - saves.push(PlatformSave::MiSTerSave(SaveInfo { - game: String::from(&system_save), - path: PathBuf::from(format!("/media/fat/saves/{system}/{system_save}")), - date_modified: modtime.timestamp(), - core, - })) - } - } - - let _ = ftp_stream.cwd("..")?; - } - let _ = ftp_stream.quit()?; - print!("\n"); - return Ok(saves); -} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 00000000..7acb6b74 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,13 @@ +import React from "react" +import ReactDOM from "react-dom/client" +import { RecoilRoot } from "recoil" +import { App } from "./app" +import "./style.css" + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + + + +) diff --git a/src/mister_ftp.rs b/src/mister_ftp.rs deleted file mode 100644 index 439cd8a3..00000000 --- a/src/mister_ftp.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub fn logged_in_ftp( - host: &str, - user: &str, - password: &str, -) -> Result { - let mut ftp_stream = suppaftp::FtpStream::connect(format!("{host}:21"))?; - ftp_stream.login(user, password)?; - Ok(ftp_stream) -} diff --git a/src/pocket_files.rs b/src/pocket_files.rs deleted file mode 100644 index 4452306c..00000000 --- a/src/pocket_files.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::{ - ffi::OsStr, - path::{Component, PathBuf}, -}; -use walkdir::WalkDir; - -pub fn find_roms_for_save( - save_name: &str, - file_types: &Vec, - pocket_path: &PathBuf, -) -> Vec { - let mut found_paths = vec![]; - let assets_path = pocket_path.join("Assets"); - - let potential_rom_names: Vec = file_types - .iter() - .map(|f| save_name.replace(".sav", format!(".{}", f.as_str()).as_str())) - .collect(); - - for entry in WalkDir::new(assets_path).into_iter().filter_map(|e| e.ok()) { - if !entry.file_type().is_file() { - continue; - } - - if let Some(file_name) = entry - .file_name() - .to_str() - .and_then(|s| Some(String::from(s))) - { - if potential_rom_names.contains(&file_name) { - found_paths.push(entry.path().to_path_buf()); - } - } - } - - found_paths -} - -pub fn convert_rom_path_to_save_path(rom_path: &PathBuf) -> PathBuf { - let file_name = format!("{}.sav", rom_path.file_stem().unwrap().to_str().unwrap()); - - let mut save_path: PathBuf = PathBuf::new(); - let components = rom_path.components(); - for component in components { - if component.as_os_str().to_string_lossy() == String::from("Assets") { - save_path = save_path.join("Saves"); - } else { - save_path = save_path.join(component); - } - } - - save_path.pop(); - save_path = save_path.join(file_name); - - save_path -} diff --git a/src/recoil/atoms.ts b/src/recoil/atoms.ts new file mode 100644 index 00000000..944a9854 --- /dev/null +++ b/src/recoil/atoms.ts @@ -0,0 +1,26 @@ +import { atom } from "recoil" + +export const pocketPathAtom = atom({ + key: "pocketPathAtom", + default: null, +}) + +export const fileSystemInvalidationAtom = atom({ + key: "fileSystemInvalidationAtom", + default: Date.now(), +}) + +export const PocketModelColourAtom = atom<"black" | "white">({ + key: "PocketModelColourAtom", + default: "black", +}) + +export const inventoryInvalidationAtom = atom({ + key: "inventoryInvalidationAtom", + default: Date.now(), +}) + +export const configInvalidationAtom = atom({ + key: "configInvalidationAtom", + default: Date.now(), +}) diff --git a/src/recoil/github/selectors.ts b/src/recoil/github/selectors.ts new file mode 100644 index 00000000..37819c42 --- /dev/null +++ b/src/recoil/github/selectors.ts @@ -0,0 +1,18 @@ +import { GithubRelease } from "../../types" +import { selectorFamily } from "recoil" + +export const GithubReleasesSelectorFamily = selectorFamily< + GithubRelease[], + { owner: string; repo: string } +>({ + key: "GithubReleasesSelectorFamily", + get: + ({ owner, repo }) => + async () => { + const response = await fetch( + `https://api.github.com/repos/${owner}/${repo}/releases` + ) + + return (await response.json()) as GithubRelease[] + }, +}) diff --git a/src/recoil/inventory/selectors.ts b/src/recoil/inventory/selectors.ts new file mode 100644 index 00000000..f7d0e85f --- /dev/null +++ b/src/recoil/inventory/selectors.ts @@ -0,0 +1,72 @@ +import { selector, selectorFamily } from "recoil" +import { Category, InventoryJSON } from "../../types" +import { inventoryInvalidationAtom } from "../atoms" +import { GithubReleasesSelectorFamily } from "../github/selectors" + +export const DownloadURLSelectorFamily = selectorFamily({ + key: "DownloadURLSelectorFamily", + get: + (coreName: string) => + async ({ get }) => { + const inventory = get(CoreInventorySelector) + const inventoryItem = inventory.data.find( + ({ identifier }) => coreName === identifier + ) + if (!inventoryItem || inventoryItem.repository.platform !== "github") + return null + + const { owner, name: repo } = inventoryItem.repository + + const githubReleaseList = get( + GithubReleasesSelectorFamily({ owner, repo }) + ) + + const zips = githubReleaseList[0].assets.filter(({ name }) => + name.endsWith(".zip") + ) + + if (zips.length === 1) return zips[0].browser_download_url + const coreZip = githubReleaseList[0].assets.find(({ name }) => { + // hopefully this doesn't get used much + const [_, core] = coreName.split(".") + const simpleCore = core.replace(/[^\x00-\x7F]/g, "").toLowerCase() + const simpleName = name.replace(/[^\x00-\x7F]/g, "").toLowerCase() + + const regex = new RegExp(`[^a-zA-Z0-9]${simpleCore}[^a-zA-Z0-9]`) + return name.endsWith(".zip") && regex.test(simpleName) + }) + + if (!coreZip) return null + + return coreZip.browser_download_url + }, +}) + +export const CoreInventorySelector = selector({ + key: "CoreInventorySelector", + get: async ({ get }) => { + get(inventoryInvalidationAtom) + const response = await fetch( + "https://joshcampbell191.github.io/openfpga-cores-inventory/api/v1/analogue-pocket/cores.json" + ) + return await response.json() + }, +}) + +export const CateogryListselector = selector({ + key: "CateogryListselector", + get: ({ get }) => { + const inventory = get(CoreInventorySelector) + + const cateogrySet = new Set( + inventory.data.map(({ release, prerelease }) => { + const releaseDetails = release ?? prerelease + if (!releaseDetails) return "Uncategorized" + const { platform } = releaseDetails + return platform.category ?? "Uncategorized" + }) + ) + + return ["All", ...Array.from(cateogrySet)] + }, +}) diff --git a/src/recoil/screenshots/selectors.ts b/src/recoil/screenshots/selectors.ts new file mode 100644 index 00000000..28a2f6cc --- /dev/null +++ b/src/recoil/screenshots/selectors.ts @@ -0,0 +1,77 @@ +import { selector, selectorFamily } from "recoil" +import { Screenshot, VideoJSON } from "../../types" +import { fileSystemInvalidationAtom } from "../atoms" +import { + invokeListFiles, + invokeReadBinaryFile, + invokeReadTextFile, +} from "../../utils/invokes" + +export const VideoJSONSelectorFamily = selectorFamily({ + key: "VideoJSONSelectorFamily", + get: + (coreName) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const jsonText = await invokeReadTextFile(`Cores/${coreName}/video.json`) + return JSON.parse(jsonText) as VideoJSON + }, +}) + +export const screenshotsListSelector = selector({ + key: "screenshotsListSelector", + get: async ({ get }) => { + get(fileSystemInvalidationAtom) + return await invokeListFiles("Memories/Screenshots") + }, +}) + +export const SingleScreenshotSelectorFamily = selectorFamily< + Screenshot | null, + string +>({ + key: "SingleScreenshotSelectorFamily", + get: + (fileName) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + + const data = await invokeReadBinaryFile( + `Memories/Screenshots/${fileName}` + ) + const buf = new Uint8Array(data) + const file = new File([buf], fileName, { type: "image/png" }) + const metadataBuffer = buf.slice(buf.length - 528) + + let utf8decoder = new TextDecoder() + // The unpacking here might not be right if there's unused ranges + + let authorName = utf8decoder + .decode(metadataBuffer.slice(0, 16 * 2)) + .replaceAll("\u0000", "") + + let coreName = utf8decoder + .decode(metadataBuffer.slice(16 * 2, 16 * 4)) + .trim() + .replaceAll("\u0000", "") + + let gameName = utf8decoder + .decode(metadataBuffer.slice(16 * 6, 16 * 20)) + .trim() + .replaceAll("\u0000", "") + + let platformName = utf8decoder + .decode(metadataBuffer.slice(metadataBuffer.length - 16 * 10)) + .replaceAll("\u0000", "") + + return { + file_name: fileName, + file, + game: gameName, + platform: platformName, + timestamp: new Date(file.lastModified), + author: authorName, + core: coreName, + } + }, +}) diff --git a/src/recoil/selectors.ts b/src/recoil/selectors.ts new file mode 100644 index 00000000..bd2fcd28 --- /dev/null +++ b/src/recoil/selectors.ts @@ -0,0 +1,332 @@ +import { selector, selectorFamily } from "recoil" +import { + CoreInfoJSON, + DataJSON, + InstanceDataJSON, + PlatformId, + PlatformInfoJSON, + PocketSyncConfig, + RequiredFileInfo, + SaveBackupPathTime, +} from "../types" +import { renderBinImage } from "../utils/renderBinImage" +import { + configInvalidationAtom, + fileSystemInvalidationAtom, + pocketPathAtom, +} from "./atoms" +import { getVersion } from "@tauri-apps/api/app" +import { decodeDataParams } from "../utils/decodeDataParams" +import { + invokeFileExists, + invokeListBackupSaves, + invokeListFiles, + invokeListSavesInZip, + invokeReadBinaryFile, + invokeReadTextFile, + invokeSaveFile, + invokeWalkDirListFiles, +} from "../utils/invokes" + +export const DataJSONSelectorFamily = selectorFamily({ + key: "DataJSONSelectorFamily", + get: + (coreName) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const jsonText = await invokeReadTextFile(`Cores/${coreName}/data.json`) + return JSON.parse(jsonText) as DataJSON + }, +}) + +export const RequiredFileInfoSelectorFamily = selectorFamily< + RequiredFileInfo[], + string +>({ + key: "DataJSONSelectorFamily", + get: + (coreName) => + async ({ get }) => { + const dataJSON = get(DataJSONSelectorFamily(coreName)) + const coreJSON = get(CoreInfoSelectorFamily(coreName)) + const [platform_id] = coreJSON.core.metadata.platform_ids + + const requiredCoreFiles = dataJSON.data.data_slots.filter( + ({ name, required, filename }) => { + return ( + // not sure why some bioses aren't required + (required || name?.toLowerCase().includes("bios")) && + filename && + coreJSON.core.metadata.platform_ids.length === 1 + ) + } + ) + + const fileInfo = await Promise.all( + requiredCoreFiles.map(async ({ filename, parameters }) => { + const path = decodeDataParams(parameters).coreSpecific + ? `Assets/${platform_id}/${coreName}` + : `Assets/${platform_id}/common` + + return { + filename: filename as string, + path, + exists: await invokeFileExists(`${path}/${filename}`), + type: "core", + } as RequiredFileInfo + }) + ) + + const instanceFileInfo = await Promise.all( + dataJSON.data.data_slots + .filter(({ required, parameters }) => { + return ( + required && + decodeDataParams(parameters).instanceJSON && + coreJSON.core.metadata.platform_ids.length === 1 + ) + }) + .map(async ({ filename, parameters }) => { + if (filename) { + // can't handle this yet + console.log("is a single filename") + } + + const path = decodeDataParams(parameters).coreSpecific + ? `Assets/${platform_id}/${coreName}/` + : `Assets/${platform_id}/common/` + + const files = await invokeWalkDirListFiles(path, [".json"]) + + return await Promise.all( + files.map(async (f) => { + const response = await invokeReadTextFile(`${path}/${f}`) + const instanceFile = JSON.parse(response) as InstanceDataJSON + const dataPath = instanceFile.instance.data_path + + return await Promise.all( + instanceFile.instance.data_slots.map( + async ({ filename, parameters }) => { + const path = decodeDataParams(parameters).coreSpecific + ? `Assets/${platform_id}/${coreName}${ + dataPath ? `/${dataPath}` : "" + }` + : `Assets/${platform_id}/common${ + dataPath ? `/${dataPath}` : "" + }` + + return { + filename: filename as string, + path, + exists: await invokeFileExists(`${path}/${filename}`), + type: "instance", + } as RequiredFileInfo + } + ) + ) + }) + ) + }) + ) + + return [...fileInfo, ...instanceFileInfo.flat(3)] + }, +}) + +export const coresListSelector = selector({ + key: "coresListSelector", + get: async ({ get }) => { + get(fileSystemInvalidationAtom) + return await invokeListFiles("Cores") + }, +}) + +export const CoreInfoSelectorFamily = selectorFamily({ + key: "CoreInfoSelectorFamily", + get: + (coreName: string) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const response = await invokeReadTextFile(`Cores/${coreName}/core.json`) + return JSON.parse(response) as CoreInfoJSON + }, +}) + +export const CoreAuthorImageSelectorFamily = selectorFamily({ + key: "CoreAuthorImageSelectorFamily", + get: + (coreName: string) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const response = await invokeReadBinaryFile(`Cores/${coreName}/icon.bin`) + return await new Promise((resolve) => { + // @ts-ignore not supported in safari + if (window.requestIdleCallback) { + requestIdleCallback( + () => { + resolve(renderBinImage(response, 36, 36, true)) + }, + { timeout: 1000 } + ) + } else { + resolve(renderBinImage(response, 36, 36, true)) + } + }) + }, +}) + +export const PlatformImageSelectorFamily = selectorFamily({ + key: "PlatformImageSelectorFamily", + get: + (platformId: PlatformId) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const response = await invokeReadBinaryFile( + `Platforms/_images/${platformId}.bin` + ) + + return await new Promise((resolve) => { + // @ts-ignore not supported in safari + if (window.requestIdleCallback) { + requestIdleCallback( + () => { + resolve(renderBinImage(response, 521, 165, true)) + }, + { timeout: 1000 } + ) + } else { + resolve(renderBinImage(response, 521, 165, true)) + } + }) + }, +}) + +export const platformsListSelector = selector({ + key: "platformsListSelector", + get: async ({ get }) => { + get(fileSystemInvalidationAtom) + return await invokeListFiles("Platforms") + }, +}) + +export const PlatformInfoSelectorFamily = selectorFamily< + PlatformInfoJSON, + PlatformId +>({ + key: "PlatformInfoSelectorFamily", + get: + (platformId: PlatformId) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const response = await invokeReadTextFile(`Platforms/${platformId}.json`) + return JSON.parse(response) as PlatformInfoJSON + }, +}) + +export const AppVersionSelector = selector({ + key: "AppVersionSelector", + get: async () => await getVersion(), +}) + +export const PocketSyncConfigSelector = selector({ + key: "PocketSyncConfigSelector", + get: async ({ get }) => { + get(configInvalidationAtom) + const pocketPath = get(pocketPathAtom) + + if (!pocketPath) { + return { + version: get(AppVersionSelector), + colour: Math.random() > 0.5 ? "white" : "black", + archive_url: null, + saves: [], + } as PocketSyncConfig + } + + const exists = await invokeFileExists("pocket-sync.json") + if (!exists) { + const defaultConfig = { + version: get(AppVersionSelector), + colour: "black", + archive_url: null, + saves: [], + } as PocketSyncConfig + + const encoder = new TextEncoder() + + await invokeSaveFile( + `${pocketPath}/pocket-sync.json`, + encoder.encode(JSON.stringify(defaultConfig, null, 2)) + ) + } + + const response = await invokeReadTextFile("pocket-sync.json") + return JSON.parse(response) as PocketSyncConfig + }, +}) + +export const FileCountSelectorFamily = selectorFamily< + number, + { path: string; extensions: string[] } +>({ + key: "FileCountSelectorFamily", + get: + ({ path, extensions }) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const files = await invokeWalkDirListFiles(path, extensions) + return files.length + }, +}) + +export const AllSavesSelector = selector({ + key: "AllSavesSelector", + get: async ({ get }) => { + get(fileSystemInvalidationAtom) + const saves = await invokeWalkDirListFiles(`Saves`, [".sav"]) + return saves.map((f) => f.replace(/^\//g, "")) + }, +}) + +export const BackupZipsSelectorFamily = selectorFamily< + { files: SaveBackupPathTime[]; exists: boolean }, + string +>({ + key: "BackupZipsSelectorFamily", + get: + (backupPath) => + async ({ get }) => { + get(fileSystemInvalidationAtom) + const backups = await invokeListBackupSaves(backupPath) + return backups + }, +}) + +export const SaveZipFilesListSelectorFamily = selectorFamily< + SaveBackupPathTime[], + string +>({ + key: "SaveZipFilesListSelectorFamily", + get: (zipPath) => async () => { + const backups = await invokeListSavesInZip(zipPath) + return backups + }, +}) + +export const AllBackupZipsFilesSelectorFamily = selectorFamily< + { zip: SaveBackupPathTime; files: SaveBackupPathTime[] }[], + string +>({ + key: "AllBackupZipsFilesSelectorFamily", + get: + (backupPath) => + async ({ get }) => { + const { files } = get(BackupZipsSelectorFamily(backupPath)) + return files.map((zip) => ({ + zip, + files: get( + SaveZipFilesListSelectorFamily(`${backupPath}/${zip.filename}`) + ), + })) + }, +}) diff --git a/src/save_compare.rs b/src/save_compare.rs deleted file mode 100644 index 60e63e77..00000000 --- a/src/save_compare.rs +++ /dev/null @@ -1,296 +0,0 @@ -use crate::{ - cores::TransformCore, - pocket_files::{convert_rom_path_to_save_path, find_roms_for_save}, - PlatformSave, SaveInfo, -}; -use std::{ - fmt, - fs::File, - io::{Read, Write}, - path::PathBuf, -}; - -#[derive(Debug, PartialEq)] -pub struct SavePair<'a> { - pocket: &'a SaveInfo, - mister: &'a SaveInfo, -} - -impl SavePair<'_> { - pub fn is_pocket_newer(&self) -> bool { - self.pocket.date_modified > self.mister.date_modified - } - - pub fn newer_save(&self) -> &SaveInfo { - if self.pocket.date_modified > self.mister.date_modified { - self.pocket - } else { - self.mister - } - } - - pub fn older_save(&self) -> &SaveInfo { - if self.pocket.date_modified > self.mister.date_modified { - self.mister - } else { - self.pocket - } - } -} - -impl<'a> fmt::Display for SavePair<'a> { - // This trait requires `fmt` with this exact signature. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let titles = match self.is_pocket_newer() { - true => ("-- Pocket (newer)", "-- MiSTer (older)"), - false => ("-- MiSTer (newer)", "-- Pocket (older)"), - }; - - write!( - f, - "{}\n{} \n\n--- VS ---\n\n{}\n{}", - titles.0, - self.newer_save(), - titles.1, - self.older_save() - ) - } -} - -#[derive(Debug, PartialEq)] -pub enum SaveComparison<'a> { - PocketOnly(&'a SaveInfo), - MiSTerOnly(&'a SaveInfo), - PocketNewer(SavePair<'a>), - MiSTerNewer(SavePair<'a>), - Conflict(SavePair<'a>), - NoSyncNeeded, -} - -impl SaveComparison<'_> { - pub fn use_mister( - &self, - ftp_stream: &mut suppaftp::FtpStream, - pocket_path: &PathBuf, - ) -> Result<(), suppaftp::FtpError> { - let mister_save_info = match self { - SaveComparison::MiSTerOnly(save_info) => &save_info, - Self::PocketNewer(save_pair) - | Self::MiSTerNewer(save_pair) - | Self::Conflict(save_pair) => &save_pair.mister, - _ => { - panic!("Attempt to use a non-existent MiSTer save"); - } - }; - let path = &mister_save_info.path; - let _ = ftp_stream.cwd(path.parent().unwrap().to_path_buf().to_str().unwrap())?; - let file_name = path.file_name().unwrap(); - let mut save_file = ftp_stream.retr_as_buffer(file_name.to_str().unwrap())?; - - let pocket_save_paths: Vec = match self { - SaveComparison::MiSTerOnly(save_info) => { - let found = find_roms_for_save( - &save_info.game, - &save_info.core.rom_filetypes(), - &pocket_path, - ) - .iter() - .map(|p| convert_rom_path_to_save_path(p)) - .collect(); - - found - } - Self::PocketNewer(save_pair) - | Self::MiSTerNewer(save_pair) - | Self::Conflict(save_pair) => vec![pocket_path.join(save_pair.pocket.path.clone())], - Self::PocketOnly(_) => panic!("Attempt to use a non-existent MiSTer save"), - Self::NoSyncNeeded => panic!("Attempt to sync when NoSyncNeeded"), - }; - - if pocket_save_paths.len() == 0 { - println!( - "Couldn't find \"{}\" on the pocket, skipping", - mister_save_info.game.replace(".sav", "") - ); - return Ok(()); - } - - println!( - "Copying {} ({}) \nMiSTer -> Pocket", - mister_save_info.game, - mister_save_info.core.to_pocket() - ); - - for pocket_save_path in pocket_save_paths { - let prefix = pocket_save_path.parent().unwrap(); - std::fs::create_dir_all(prefix).unwrap(); - - let mut file = File::create(pocket_save_path).unwrap(); - let mut buf: Vec = Vec::new(); - save_file.read_to_end(&mut buf).unwrap(); - file.write(&buf).unwrap(); - } - - return Ok(()); - } - - pub fn use_pocket( - &self, - ftp_stream: &mut suppaftp::FtpStream, - pocket_path: &PathBuf, - ) -> Result<(), suppaftp::FtpError> { - let pocket_save_info = match self { - SaveComparison::PocketOnly(save_info) => &save_info, - Self::PocketNewer(save_pair) - | Self::MiSTerNewer(save_pair) - | Self::Conflict(save_pair) => &save_pair.pocket, - _ => { - panic!("Attempt to use a non-existent Pocket save"); - } - }; - let path = &pocket_save_info.path; - let file_name = path.file_name().unwrap(); - let mister_save_path = match self { - SaveComparison::PocketOnly(save_info) => { - pocket_path.join(format!("/media/fat/saves/{}", save_info.core.to_mister())) - } - Self::PocketNewer(save_pair) - | Self::MiSTerNewer(save_pair) - | Self::Conflict(save_pair) => save_pair - .mister - .path - .clone() - .parent() - .unwrap() - .to_path_buf(), - Self::MiSTerOnly(_) => panic!("Attempt to use a non-existent MiSTer save"), - Self::NoSyncNeeded => panic!("Attempt to sync when NoSyncNeeded"), - }; - - let mut file = File::open(path).unwrap(); - - let mister_path_buf = &mister_save_path.to_path_buf(); - let mister_path = mister_path_buf.to_str().unwrap(); - - println!( - "Copying {} ({}) \nPocket -> MiSTer\n---", - pocket_save_info.game, - pocket_save_info.core.to_mister() - ); - - ftp_stream.cwd(mister_path)?; - ftp_stream.put_file(file_name.to_str().unwrap(), &mut file)?; - - return Ok(()); - } -} - -pub fn check_save<'a>( - save: &'a PlatformSave, - pocket_saves: &'a Vec, - mister_saves: &'a Vec, - last_merge: i64, -) -> SaveComparison<'a> { - match save { - PlatformSave::PocketSave(pocket_save_info) => { - if let Some(mister_save_info) = - find_matching_mister_save(pocket_save_info, mister_saves) - { - return get_comparison(pocket_save_info, mister_save_info, last_merge); - } else { - return SaveComparison::PocketOnly(pocket_save_info); - } - } - PlatformSave::MiSTerSave(mister_save_info) => { - if let Some(pocket_save_info) = - find_matching_pocket_save(mister_save_info, pocket_saves) - { - return get_comparison(pocket_save_info, mister_save_info, last_merge); - } else { - return SaveComparison::MiSTerOnly(mister_save_info); - } - } - } -} - -fn get_comparison<'a>( - pocket_save_info: &'a SaveInfo, - mister_save_info: &'a SaveInfo, - last_merge: i64, -) -> SaveComparison<'a> { - if mister_save_info.date_modified < 86400 { - // MiSTer save was updated while the RTC wasn't running - raise as a conflict to be safe - return SaveComparison::Conflict(SavePair { - pocket: pocket_save_info, - mister: mister_save_info, - }); - } - - if pocket_save_info.date_modified < last_merge && mister_save_info.date_modified < last_merge { - return SaveComparison::NoSyncNeeded; - } - - if pocket_save_info.date_modified > last_merge && mister_save_info.date_modified > last_merge { - return SaveComparison::Conflict(SavePair { - pocket: pocket_save_info, - mister: mister_save_info, - }); - } - - if mister_save_info.date_modified > pocket_save_info.date_modified { - return SaveComparison::MiSTerNewer(SavePair { - pocket: pocket_save_info, - mister: &mister_save_info, - }); - } else { - return SaveComparison::PocketNewer(SavePair { - pocket: pocket_save_info, - mister: mister_save_info, - }); - } -} - -fn find_matching_mister_save<'a>( - save: &SaveInfo, - saves: &'a Vec, -) -> Option<&'a SaveInfo> { - for mister_save in saves { - if let PlatformSave::MiSTerSave(mister_save) = mister_save { - if mister_save.core == save.core && mister_save.game == save.game { - return Some(&mister_save); - } - } - } - return None; -} - -fn find_matching_pocket_save<'a>( - save: &SaveInfo, - saves: &'a Vec, -) -> Option<&'a SaveInfo> { - for pocket_save in saves { - if let PlatformSave::PocketSave(pocket_save) = pocket_save { - if pocket_save.core == save.core && pocket_save.game == save.game { - return Some(&pocket_save); - } - } - } - return None; -} - -pub fn remove_duplicates<'a>(save_comparisons: Vec>) -> Vec> { - let mut singles: Vec = Vec::new(); - - for save_comparison in save_comparisons { - match &save_comparison { - SaveComparison::NoSyncNeeded => singles.push(save_comparison), - _ => { - if !singles.contains(&save_comparison) { - singles.push(save_comparison) - } - } - } - } - - singles -} diff --git a/src/style.css b/src/style.css new file mode 100644 index 00000000..5901d9ed --- /dev/null +++ b/src/style.css @@ -0,0 +1,109 @@ +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color: #f6f6f6; + --background-colour: #2f2f2f; + --hover-colour: #222; + --info-colour: #111; + --light-colour: #555; + --green-colour: rgb(88, 144, 80); + --red-colour: rgb(200, 80, 88); + background-color: var(--background-colour); + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; + accent-color: white; +} + +body { + margin: 0; + padding: 0; + overflow-x: hidden; +} + +.container { + margin: 0; + padding: 10vh 0; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + height: 100vh; + box-sizing: border-box; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: 0.75s; +} + +.logo.tauri:hover { + filter: drop-shadow(0 0 2em #24c8db); +} + +.row { + display: flex; + justify-content: center; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +h1 { + text-align: center; + font-family: "Analogue"; + font-size: 4rem; + font-smooth: never; + -webkit-font-smoothing : none; +} + +h2 { + text-align: left; + font-family: "Analogue"; + font-size: 3rem; + font-smooth: never; + -webkit-font-smoothing : none; + padding: 0 10px; + margin-bottom: 15px; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + color: #ffffff; + background-color: #0f0f0f98; + transition: border-color 0.25s; + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); +} + +button { + cursor: pointer; +} + +button:hover { + border-color: #396cd8; +} + +input, +button { + outline: none; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..4742b702 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,178 @@ +export type Screenshot = { + file_name: string + file: File + platform: string + game: string + author: string + core: string + timestamp: Date +} + +export type VideoJSON = { + video: { + magic: "APF_VER_1" + scaler_modes: { + width: number + height: number + aspect_w: number + aspect_h: number + rotation: number + mirror: 0 | 1 + }[] + } +} + +export type DataJSON = { + data: { + magic: "APF_VER_1" + data_slots: DataSlotJSON[] + } +} + +export type InstanceDataJSON = { + instance: { + data_path?: string + data_slots: DataSlotJSON[] + } +} + +type DataSlotJSON = { + name?: string + required?: boolean + parameters: number | string + extensions?: string[] + filename?: string +} + +export type RequiredFileInfo = { + filename: string + path: string + exists: boolean + type: "core" | "instance" +} + +export type PlatformId = string +export type Category = string +export type AuthorName = string +export type Semver = `${number}.${number}.${number}` + +export type PlatformInfoJSON = { + platform: { + category: Category + name: string + year: number + manufacturer: string + } +} + +export type CoreInfoJSON = { + core: { + magic: "APF_VER_1" + metadata: { + platform_ids: PlatformId[] + shortname: string + description: string + author: AuthorName + url?: string + version: Semver | string + date_release: string + } + framework: { + target_product: "Analogue Pocket" + version_required: string + sleep_supported: boolean + dock: { + supported: boolean + analog_output: boolean + } + hardware: { + link_port: boolean + cartridge_adapter: -1 | 0 + } + } + cores: { + name: string + id: number | string + filename: string + }[] + } +} + +export type InventoryJSON = { + data: InventoryItem[] +} + +export type InventoryItem = { + identifier: string + platform: PlatformId + repository: { + platform: "github" | string + owner: string + name: string + } + release?: InventoryItemRelease + prerelease?: InventoryItemRelease + sponsor?: { + [k: string]: string + } +} + +type InventoryItemRelease = { + tag_name: Semver | string + release_date: string + platform: { + category: string + name: string + manufacturer: string + year: number + } + assets: [ + { + platform: PlatformId + filename?: string + extensions?: string[] + } + ] +} + +export type GithubRelease = { + html_url: string + id: number + tag_name: string + name: string + body: string + draft: boolean + prerelease: boolean + created_at: string + published_at: string + assets: { + browser_download_url: string + name: string + label: string + content_type: string + size: 1024 + }[] +} + +export type InstallDetails = { + success: boolean + files: { path: string; exists: boolean }[] +} + +export type PocketSyncConfig = { + version: string + colour: "white" | "black" + archive_url: string | null + saves: SaveConfig[] +} + +export type SaveConfig = { + type: "zip" + backup_location: string + backup_count: number +} + +export type SaveBackupPathTime = { + filename: string + last_modified: number +} diff --git a/src/user_input.rs b/src/user_input.rs deleted file mode 100644 index 28435805..00000000 --- a/src/user_input.rs +++ /dev/null @@ -1,96 +0,0 @@ -use question::{Answer, Question}; - -use crate::save_compare::{SaveComparison, SavePair}; - -#[derive(PartialEq)] -pub enum UserInput { - Ok, - Cancel, - UseMister, - UsePocket, - Skip, -} - -pub fn choose_save(save_pair: &SavePair) -> UserInput { - println!("{}", save_pair); - let answer = Question::new("Use MiSTer or Pocket save?\n([m]ister/[p]ocket/[s]kip):") - .acceptable(vec!["pocket", "mister", "p", "m", "skip", "s"]) - .until_acceptable() - .ask(); - - match answer { - Some(Answer::RESPONSE(response)) => match response.as_str() { - "mister" | "m" => UserInput::UseMister, - "pocket" | "p" => UserInput::UsePocket, - _ => UserInput::Cancel, - }, - _ => UserInput::Cancel, - } -} - -pub fn report_status(saves: &Vec) -> UserInput { - let (mister_count, pocket_count, conflict_count, no_sync_needed_count) = - count_save_types(&saves); - println!( - "Found {} Saves\nWith {} conflicts, {} newer MiSTer saves, {} newer Pocket saves, and {} which don't need synced", - saves.len(), - conflict_count, - mister_count, - pocket_count, - no_sync_needed_count - ); - - if saves.len() == no_sync_needed_count as usize { - println!("No saves to sync! Exiting..."); - std::process::exit(0); - } - - let answer = Question::new("Do you want to continue the sync?") - .yes_no() - .default(Answer::YES) - .show_defaults() - .tries(3) - .ask(); - - match answer { - Some(Answer::YES) => UserInput::Ok, - _ => UserInput::Cancel, - } -} - -fn count_save_types(saves: &Vec) -> (u32, u32, u32, u32) { - let mut mister_count: u32 = 0; - let mut pocket_count: u32 = 0; - let mut conflict_count: u32 = 0; - let mut no_sync_needed_count: u32 = 0; - - for save in saves { - match save { - SaveComparison::MiSTerOnly(_) => { - mister_count += 1; - } - SaveComparison::MiSTerNewer(_) => { - mister_count += 1; - } - SaveComparison::PocketOnly(_) => { - pocket_count += 1; - } - SaveComparison::PocketNewer(_) => { - pocket_count += 1; - } - SaveComparison::Conflict(_) => { - conflict_count += 1; - } - _ => { - no_sync_needed_count += 1; - } - } - } - - ( - mister_count, - pocket_count, - conflict_count, - no_sync_needed_count, - ) -} diff --git a/src/utils/decodeDataParams.ts b/src/utils/decodeDataParams.ts new file mode 100644 index 00000000..c701b69f --- /dev/null +++ b/src/utils/decodeDataParams.ts @@ -0,0 +1,11 @@ +export const decodeDataParams = (rawParams: string | number) => { + const parms = typeof rawParams === "string" ? Number(rawParams) : rawParams + + return { + userReloadable: (parms & 1) === 1, + coreSpecific: (parms & 2) === 2, + nonVolitileFilename: (parms & 0b000000100) === 0b000000100, + readOnly: (parms & 0b000001000) === 0b000001000, + instanceJSON: (parms & 0b000010000) === 0b000010000, + } +} diff --git a/src/utils/invokes.ts b/src/utils/invokes.ts new file mode 100644 index 00000000..e1db33d6 --- /dev/null +++ b/src/utils/invokes.ts @@ -0,0 +1,71 @@ +import { invoke } from "@tauri-apps/api" +import { SaveBackupPathTime } from "../types" + +export const invokeOpenPocket = async () => invoke("open_pocket") + +export const invokeListFiles = async (path: string) => + invoke("list_files", { + path, + }) + +export const invokeReadTextFile = async (path: string) => + invoke("read_text_file", { + path, + }) + +export const invokeReadBinaryFile = async (path: string) => + invoke("read_binary_file", { + path, + }) + +export const invokeWalkDirListFiles = async ( + path: string, + extensions: string[] +) => + invoke("walkdir_list_files", { + path, + extensions, + }) + +export const invokeSaveFile = async (path: string, buffer: Uint8Array) => + invoke("save_file", { + path, + buffer: Array.prototype.slice.call(buffer), + }) + +export const invokeFileExists = async (path: string) => + invoke("file_exists", { + path, + }) + +export const invokeUninstallCore = async (coreName: string) => + invoke("uninstall_core", { + coreName, + }) + +export const invokeBackupSaves = async ( + savePaths: string[], + zipPath: string, + maxCount: number +) => invoke("backup_saves", { savePaths, zipPath, maxCount }) + +export const invokeListBackupSaves = async (backupPath: string) => { + const { files, exists } = await invoke<{ + files: SaveBackupPathTime[] + exists: boolean + }>("list_backup_saves", { + backupPath, + }) + return { + files: [...files].sort((a, b) => a.last_modified - b.last_modified), + exists, + } +} + +export const invokeListSavesInZip = async (zipPath: string) => { + return invoke("list_saves_in_zip", { zipPath }) +} + +export const invokeRestoreZip = async (zipPath: string, filePath: string) => { + return invoke("restore_save", { zipPath, filePath }) +} diff --git a/src/utils/renderBinImage.ts b/src/utils/renderBinImage.ts new file mode 100644 index 00000000..5f4b4492 --- /dev/null +++ b/src/utils/renderBinImage.ts @@ -0,0 +1,34 @@ +export const renderBinImage = ( + image: Uint8Array, + width: number, + height: number, + invert: boolean +): string => { + const canvas = document.createElement("canvas") + const context = canvas.getContext("2d") + if (!context) throw new Error("Failed to get canvas context") + + canvas.width = width + canvas.height = height + + const halfWidth = Math.ceil(width / 2) + const halfHeight = Math.ceil(height / 2) + + context.translate(halfWidth, halfHeight) + context.rotate(Math.PI / 2) + context.translate(-halfHeight, -halfWidth) + + let index = 0 + for (let y = 0; y < width; y++) { + for (let x = 0; x < height; x++) { + const value = image[index] + const brightness = invert ? 255 - value : value + context.fillStyle = `rgb(${brightness}, ${brightness}, ${brightness})` + context.fillRect(x, y, 1, 1) + + index = index + 2 + } + } + + return canvas.toDataURL() +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..3d0a51a8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 00000000..9d31e2ae --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..851d6945 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from "vite" +import react from "@vitejs/plugin-react" +import postcssNesting from "postcss-nesting" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + css: { + postcss: { + plugins: [postcssNesting], + }, + }, + + // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` + // prevent vite from obscuring rust errors + clearScreen: false, + // tauri expects a fixed port, fail if that port is not available + server: { + port: 1420, + strictPort: true, + }, + // to make use of `TAURI_DEBUG` and other env variables + // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand + envPrefix: ["VITE_", "TAURI_"], + build: { + // Tauri supports es2021 + target: ["es2021", "chrome100", "safari13"], + // don't minify for debug builds + minify: !process.env.TAURI_DEBUG ? "esbuild" : false, + // produce sourcemaps for debug builds + sourcemap: !!process.env.TAURI_DEBUG, + }, +})