diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..15513db42c7df86b9c6576253a4f85d7db50e8ea --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + } +} diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..176a458f94e0ea5272ce67c36bf30b6be9caf623 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,35 +1 @@ -*.7z filter=lfs diff=lfs merge=lfs -text -*.arrow filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text -*.bz2 filter=lfs diff=lfs merge=lfs -text -*.ckpt filter=lfs diff=lfs merge=lfs -text -*.ftz filter=lfs diff=lfs merge=lfs -text -*.gz filter=lfs diff=lfs merge=lfs -text -*.h5 filter=lfs diff=lfs merge=lfs -text -*.joblib filter=lfs diff=lfs merge=lfs -text -*.lfs.* filter=lfs diff=lfs merge=lfs -text -*.mlmodel filter=lfs diff=lfs merge=lfs -text -*.model filter=lfs diff=lfs merge=lfs -text -*.msgpack filter=lfs diff=lfs merge=lfs -text -*.npy filter=lfs diff=lfs merge=lfs -text -*.npz filter=lfs diff=lfs merge=lfs -text -*.onnx filter=lfs diff=lfs merge=lfs -text -*.ot filter=lfs diff=lfs merge=lfs -text -*.parquet filter=lfs diff=lfs merge=lfs -text -*.pb filter=lfs diff=lfs merge=lfs -text -*.pickle filter=lfs diff=lfs merge=lfs -text -*.pkl filter=lfs diff=lfs merge=lfs -text -*.pt filter=lfs diff=lfs merge=lfs -text -*.pth filter=lfs diff=lfs merge=lfs -text -*.rar filter=lfs diff=lfs merge=lfs -text -*.safetensors filter=lfs diff=lfs merge=lfs -text -saved_model/**/* filter=lfs diff=lfs merge=lfs -text -*.tar.* filter=lfs diff=lfs merge=lfs -text -*.tar filter=lfs diff=lfs merge=lfs -text -*.tflite filter=lfs diff=lfs merge=lfs -text -*.tgz filter=lfs diff=lfs merge=lfs -text -*.wasm filter=lfs diff=lfs merge=lfs -text -*.xz filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.zst filter=lfs diff=lfs merge=lfs -text -*tfevents* filter=lfs diff=lfs merge=lfs -text +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..784574978179b77cf4882da30db4b9df7c6f661d --- /dev/null +++ b/.gitignore @@ -0,0 +1,134 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IDE +.vscode/ +playground/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..47b748ffd51100c3b5ce38acafc0b9bee471e237 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "tabWidth": 4, + "useTabs": false, + "printWidth": 120 +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..98b56f5228cf973798ce8e94921ac7b1496c64cc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Dylan Ebert + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index bf84ae9e0556814faade4e9aa871d18680756f2c..9377cf47b2fad088d6bbb70486f5c4126878bd7e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,106 @@ ---- -title: Gsplat Library -emoji: 📊 -colorFrom: gray -colorTo: blue -sdk: static -pinned: false -license: mit -short_description: gsplat_library based on dylanebert library ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# gsplat.js + +#### JavaScript Gaussian Splatting library + +gsplat.js is an easy-to-use, general-purpose, open-source 3D Gaussian Splatting library, providing functionality similar to [three.js](https://github.com/mrdoob/three.js) but for Gaussian Splatting. + +### Quick Start + +- **Live Viewer Demo:** Explore this library in action in the 🤗 [Hugging Face demo](https://huggingface.co/spaces/dylanebert/igf). Note: May not work on all devices; use `Bonsai` for the lowest memory requirements. +- **Editor Demo:** Try new real-time updates and editing features in the [gsplat.js editor](https://huggingface.co/spaces/dylanebert/gsplat-editor). +- **Code Example:** Start coding immediately with this [jsfiddle example](https://jsfiddle.net/wdn6vasc/). + +### Installation + +**Prerequisites**: Ensure your development environment supports ES6 modules. + +1. **Set Up a Project:** (If not already set up) + + Install [Node.js](https://nodejs.org/en/download/) and [NPM](https://www.npmjs.com/get-npm), then initialize a new project using a module bundler like [Vite](https://vitejs.dev/): + + ```bash + npm create vite@latest gsplat -- --template vanilla-ts + ``` + +2. **Test Your Environment:** + + ```bash + cd gsplat + npm install + npm run dev + ``` + +3. **Install gsplat.js:** + + ```bash + npm install --save gsplat + ``` + +### Usage + +#### Creating a Scene + +- Import **gsplat.js** components and set up a basic scene. +- Load Gaussian Splatting data and start a rendering loop. + +(in `src/main.ts` if you followed the Vite setup) + +```js +import * as SPLAT from "gsplat"; + +const scene = new SPLAT.Scene(); +const camera = new SPLAT.Camera(); +const renderer = new SPLAT.WebGLRenderer(); +const controls = new SPLAT.OrbitControls(camera, renderer.canvas); + +async function main() { + const url = "https://huggingface.co/datasets/dylanebert/3dgs/resolve/main/bonsai/bonsai-7k.splat"; + + await SPLAT.Loader.LoadAsync(url, scene, () => {}); + + const frame = () => { + controls.update(); + renderer.render(scene, camera); + + requestAnimationFrame(frame); + }; + + requestAnimationFrame(frame); +} + +main(); +``` + +This script sets up a basic scene with Gaussian Splatting data loaded from URL and starts a rendering loop. + +### FAQ + +**Q: Can I use .ply files?** + +A: Yes, gsplat.js supports `.ply` files. See the [ply-converter example](https://github.com/dylanebert/gsplat.js/blob/main/examples/ply-converter/src/main.ts) for details on how to convert `.ply` to `.splat`. Alternatively, convert PLY files from URL in this [jsfiddle example](https://jsfiddle.net/2sq3pvdt/1/). + +**Q: What are .splat files?** + +A: `.splat` files are a compact form of the splat data, offering quicker loading times than `.ply` files. They consist of a raw Uint8Array buffer. + +> ⚠️ The `.splat` format does not contain SH coefficients, so colors are not view-dependent. + +**Q: Can I convert .splat files to .ply?** + +A: Yes, see the commented code in the [ply-converter example](https://github.com/dylanebert/gsplat.js/blob/main/examples/ply-converter/src/main.ts). Alternatively, convert `.splat` to `.ply` from URL in this [jsfiddle example](https://jsfiddle.net/aL81ds3e/). + +> ⚠️ When converting `.ply` -> `.splat` -> `.ply`, SH coefficients will be lost. + +### License + +This project is released under the MIT license. It is built upon several other open-source projects: + +- [three.js](https://github.com/mrdoob/three.js), MIT License (c) 2010-2023 three.js authors +- [antimatter15/splat](https://github.com/antimatter15/splat), MIT License (c) 2023 Kevin Kwok +- [UnityGaussianSplatting](https://github.com/aras-p/UnityGaussianSplatting), MIT License (c) 2023 Aras Pranckevičius + +Please note that the license of the original [3D Gaussian Splatting](https://github.com/graphdeco-inria/gaussian-splatting) research project is non-commercial. While this library provides an open-source rendering implementation, users should consider the source of the splat data separately. + +### Contact + +Feel free to open issues, join the [Hugging Face Discord](https://hf.co/join/discord), or email me directly at [dylan@huggingface.co](mailto:dylan@huggingface.co). diff --git a/compile_wasm.sh b/compile_wasm.sh new file mode 100644 index 0000000000000000000000000000000000000000..7c1a544d822058c6bd561908b7d8a77511756baf --- /dev/null +++ b/compile_wasm.sh @@ -0,0 +1,18 @@ +#!/bin/bash +emcc --bind wasm/sort.cpp -Oz -o src/wasm/sort.js \ + -s EXPORT_ES6=1 \ + -s MODULARIZE=1 \ + -s EXPORT_NAME=loadWasm \ + -s EXPORTED_FUNCTIONS="[_sort, _malloc, _free]" \ + -s SINGLE_FILE=1 \ + -s ALLOW_MEMORY_GROWTH=1 \ + -s ENVIRONMENT=worker + +emcc --bind wasm/data.cpp -Oz -o src/wasm/data.js \ + -s EXPORT_ES6=1 \ + -s MODULARIZE=1 \ + -s EXPORT_NAME=loadWasm \ + -s EXPORTED_FUNCTIONS="[_pack, _malloc, _free]" \ + -s SINGLE_FILE=1 \ + -s ALLOW_MEMORY_GROWTH=1 \ + -s ENVIRONMENT=worker diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000000000000000000000000000000000000..20031a5a6ebd073e8e68fa0a3cc95cd97ac89965 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import("ts-jest").JestConfigWithTsJest} */ +export default { + preset: "ts-jest", + testEnvironment: "node", +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..91b9954abea30365271f4777dc0155e6071c0b44 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5864 @@ +{ + "name": "gsplat", + "version": "0.2.6", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gsplat", + "version": "0.2.6", + "license": "MIT", + "devDependencies": { + "@jest/globals": "^29.7.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.5", + "@types/jest": "^29.5.8", + "@types/node": "^20.8.10", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.1", + "jest": "^29.7.0", + "ncp": "^2.0.0", + "prettier": "^3.0.3", + "rollup": "^4.3.0", + "rollup-plugin-web-worker-loader": "^1.6.1", + "ts-jest": "^29.1.1", + "typescript": "^5.2.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.5.tgz", + "integrity": "sha512-rnMHrGBB0IUEv69Q8/JGRD/n4/n6b3nfpufUu26axhUcboUzv/twfZU8fIBbTOphRAe0v8EyxzeDpKXqGHfyDA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", + "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.3.0.tgz", + "integrity": "sha512-/4pns6BYi8MXdwnXM44yoGAcFYVHL/BYlB2q1HXZ6AzH++LaiEVWFpBWQ/glXhbMbv3E3o09igrHFbP/snhAvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.3.0.tgz", + "integrity": "sha512-nLO/JsL9idr416vzi3lHm3Xm+QZh4qHij8k3Er13kZr5YhL7/+kBAx84kDmPc7HMexLmwisjDCeDIKNFp8mDlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-dGhVBlllt4iHwTGy21IEoMOTN5wZoid19zEIxsdY29xcEiOEHqzDa7Sqrkh5OE7LKCowL61eFJXxYe/+pYa7ZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.3.0.tgz", + "integrity": "sha512-h8wRfHeLEbU3NzaP1Oku7BYXCJQiTRr+8U0lklyOQXxXiEpHLL8tk1hFl+tezoRKLcPJD7joKaK74ASsqt3Ekg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-wP4VgR/gfV18sylTuym3sxRTkAgUR2vh6YLeX/GEznk5jCYcYSlx585XlcUcl0c8UffIZlRJ09raWSX3JDb4GA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-v/14JCYVkqRSJeQbxFx4oUkwVQQw6lFMN7bd4vuARBc3X2lmomkxBsc+BFiIDL/BK+CTx5AOh/k9XmqDnKWRVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-tNhfYqFH5OxtRzfkTOKdgFYlPSZnlDLNW4+leNEvQZhwTJxoTwsZAAhR97l3qVry/kkLyJPBK+Q8EAJLPinDIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-pw77m8QywdsoFdFOgmc8roF1inBI0rciqzO8ffRUgLoq7+ee9o5eFqtEcS6hHOOplgifAUUisP8cAnwl9nUYPw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-tJs7v2MnV2F8w6X1UpPHl/43OfxjUy9SuJ2ZPoxn79v9vYteChVYO/ueLHCpRMmyTUIVML3N9z4azl9ENH8Xxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-OKGxp6kATQdTyI2DF+e9s+hB3/QZB45b6e+dzcfW1SUqiF6CviWyevhmT4USsMEdP3mlpC9zxLz3Oh+WaTMOSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.3.0.tgz", + "integrity": "sha512-DDZ5AH68JJ2ClQFEA1aNnfA7Ybqyeh0644rGbrLOdNehTmzfICHiWSn0OprzYi9HAshTPQvlwrM+bi2kuaIOjQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-dMvGV8p92GQ8jhNlGIKpyhVZPzJlT258pPrM5q2F8lKcc9Iv9BbfdnhX1OfinYWnb9ms5zLw6MlaMnqLfUkKnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz", + "integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz", + "integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", + "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz", + "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/type-utils": "6.9.1", + "@typescript-eslint/utils": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz", + "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz", + "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz", + "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/utils": "6.9.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz", + "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz", + "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz", + "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/typescript-estree": "6.9.1", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz", + "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.9.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001561", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz", + "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.578", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.578.tgz", + "integrity": "sha512-V0ZhSu1BQZKfG0yNEL6Dadzik8E1vAzfpVOapdSiT9F6yapEJ3Bk+4tZ4SMPdWiUchCgnM/ByYtBzp5ntzDMIA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.1.tgz", + "integrity": "sha512-opCrKqbthmq3SKZ10mFMQG9dk3fTa3quaOLD35kJa5ejwZHd9xAr+kLuziiZz2cG32s4lMZxNdmdcEQnTDP4+g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/jest-changed-files/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/jest-changed-files/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", + "dev": true, + "bin": { + "ncp": "bin/ncp" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.3.0.tgz", + "integrity": "sha512-scIi1NrKLDIYSPK66jjECtII7vIgdAMFmFo8h6qm++I6nN9qDSV35Ku6erzGVqYjx+lj+j5wkusRMr++8SyDZg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.3.0", + "@rollup/rollup-android-arm64": "4.3.0", + "@rollup/rollup-darwin-arm64": "4.3.0", + "@rollup/rollup-darwin-x64": "4.3.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.3.0", + "@rollup/rollup-linux-arm64-gnu": "4.3.0", + "@rollup/rollup-linux-arm64-musl": "4.3.0", + "@rollup/rollup-linux-x64-gnu": "4.3.0", + "@rollup/rollup-linux-x64-musl": "4.3.0", + "@rollup/rollup-win32-arm64-msvc": "4.3.0", + "@rollup/rollup-win32-ia32-msvc": "4.3.0", + "@rollup/rollup-win32-x64-msvc": "4.3.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-web-worker-loader": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-web-worker-loader/-/rollup-plugin-web-worker-loader-1.6.1.tgz", + "integrity": "sha512-4QywQSz1NXFHKdyiou16mH3ijpcfLtLGOrAqvAqu1Gx+P8+zj+3gwC2BSL/VW1d+LW4nIHC8F7d7OXhs9UdR2A==", + "dev": true, + "peerDependencies": { + "rollup": "^1.9.2 || ^2.0.0" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smob": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", + "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..25dd6937ef8776b9b55659c539afa7fc73f73491 --- /dev/null +++ b/package.json @@ -0,0 +1,58 @@ +{ + "name": "gsplat", + "version": "1.2.4", + "description": "JavaScript Gaussian Splatting library", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "scripts": { + "build:wasm": "sh ./compile_wasm.sh", + "copy:wasm": "ncp ./src/wasm ./dist/wasm", + "build": "npm run build:wasm && rollup -c && npm run copy:wasm", + "test": "jest --passWithNoTests", + "lint": "eslint \"src/**/*.ts\" \"examples/**/*.ts\"", + "format": "prettier --write \"src/**/*.ts\" \"examples/**/*.ts\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dylanebert/splat.js.git" + }, + "keywords": [ + "gsplat", + "gaussian splatting", + "javascript", + "3d", + "webgl" + ], + "author": "dylanebert", + "license": "MIT", + "bugs": { + "url": "https://github.com/dylanebert/splat.js/issues" + }, + "homepage": "https://github.com/dylanebert/splat.js#readme", + "devDependencies": { + "@jest/globals": "^29.7.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.5", + "@types/jest": "^29.5.8", + "@types/node": "^20.8.10", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.1", + "jest": "^29.7.0", + "ncp": "^2.0.0", + "prettier": "^3.0.3", + "rollup": "^4.3.0", + "rollup-plugin-web-worker-loader": "^1.6.1", + "ts-jest": "^29.1.1", + "typescript": "^5.2.2" + }, + "files": [ + "dist/**/*" + ] +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000000000000000000000000000000000000..429a5b889b14ab6164280afd90bc2f1144f08b90 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,27 @@ +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import terser from "@rollup/plugin-terser"; +import typescript from "@rollup/plugin-typescript"; +import workerLoader from "rollup-plugin-web-worker-loader"; +import replace from "@rollup/plugin-replace"; + +export default { + input: "src/index.ts", + output: { + dir: "dist", + format: "esm", + name: "gsplat", + sourcemap: true, + plugins: [terser()], + }, + plugins: [ + replace({ + "import.meta.url": "''", + preventAssignment: true, + }), + workerLoader({ targetPlatform: "browser" }), + resolve({ browser: true, preferBuiltins: false }), + commonjs(), + typescript(), + ], +}; diff --git a/src/cameras/Camera.ts b/src/cameras/Camera.ts new file mode 100644 index 0000000000000000000000000000000000000000..3390da55853dac2af770414d56b855f399912171 --- /dev/null +++ b/src/cameras/Camera.ts @@ -0,0 +1,42 @@ +import { CameraData } from "./CameraData"; +import { Object3D } from "../core/Object3D"; +import { Vector3 } from "../math/Vector3"; +import { Vector4 } from "../math/Vector4"; + +class Camera extends Object3D { + private _data: CameraData; + + screenPointToRay: (x: number, y: number) => Vector3; + + constructor(camera: CameraData | undefined = undefined) { + super(); + + this._data = camera ? camera : new CameraData(); + this._position = new Vector3(0, 0, -5); + + this.update = () => { + this.data.update(this.position, this.rotation); + }; + + this.screenPointToRay = (x: number, y: number) => { + const clipSpaceCoords = new Vector4(x, y, -1, 1); + const inverseProjectionMatrix = this._data.projectionMatrix.invert(); + const cameraSpaceCoords = clipSpaceCoords.multiply(inverseProjectionMatrix); + const inverseViewMatrix = this._data.viewMatrix.invert(); + const worldSpaceCoords = cameraSpaceCoords.multiply(inverseViewMatrix); + const worldSpacePosition = new Vector3( + worldSpaceCoords.x / worldSpaceCoords.w, + worldSpaceCoords.y / worldSpaceCoords.w, + worldSpaceCoords.z / worldSpaceCoords.w, + ); + const direction = worldSpacePosition.subtract(this.position).normalize(); + return direction; + }; + } + + get data() { + return this._data; + } +} + +export { Camera }; diff --git a/src/cameras/CameraData.ts b/src/cameras/CameraData.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a9071cf9c943325f0f89cb41f7fe4cf8b8f4a2a --- /dev/null +++ b/src/cameras/CameraData.ts @@ -0,0 +1,127 @@ +import { Quaternion } from "../math/Quaternion"; +import { Matrix3 } from "../math/Matrix3"; +import { Matrix4 } from "../math/Matrix4"; +import { Vector3 } from "../math/Vector3"; + +class CameraData { + private _fx: number = 1132; + private _fy: number = 1132; + private _near: number = 0.1; + private _far: number = 100; + + private _width: number = 512; + private _height: number = 512; + + private _projectionMatrix: Matrix4 = new Matrix4(); + private _viewMatrix: Matrix4 = new Matrix4(); + private _viewProj: Matrix4 = new Matrix4(); + + update: (position: Vector3, rotation: Quaternion) => void; + setSize: (width: number, height: number) => void; + + private _updateProjectionMatrix: () => void; + + constructor() { + this._updateProjectionMatrix = () => { + // prettier-ignore + this._projectionMatrix = new Matrix4( + 2 * this.fx / this.width, 0, 0, 0, + 0, -2 * this.fy / this.height, 0, 0, + 0, 0, this.far / (this.far - this.near), 1, + 0, 0, -(this.far * this.near) / (this.far - this.near), 0 + ); + + this._viewProj = this.projectionMatrix.multiply(this.viewMatrix); + }; + + this.update = (position: Vector3, rotation: Quaternion) => { + const R = Matrix3.RotationFromQuaternion(rotation).buffer; + const t = position.flat(); + + // prettier-ignore + this._viewMatrix = new Matrix4( + R[0], R[1], R[2], 0, + R[3], R[4], R[5], 0, + R[6], R[7], R[8], 0, + -t[0] * R[0] - t[1] * R[3] - t[2] * R[6], + -t[0] * R[1] - t[1] * R[4] - t[2] * R[7], + -t[0] * R[2] - t[1] * R[5] - t[2] * R[8], + 1, + ); + + this._viewProj = this.projectionMatrix.multiply(this.viewMatrix); + }; + + this.setSize = (width: number, height: number) => { + this._width = width; + this._height = height; + this._updateProjectionMatrix(); + }; + } + + get fx() { + return this._fx; + } + + set fx(fx: number) { + if (this._fx !== fx) { + this._fx = fx; + this._updateProjectionMatrix(); + } + } + + get fy() { + return this._fy; + } + + set fy(fy: number) { + if (this._fy !== fy) { + this._fy = fy; + this._updateProjectionMatrix(); + } + } + + get near() { + return this._near; + } + + set near(near: number) { + if (this._near !== near) { + this._near = near; + this._updateProjectionMatrix(); + } + } + + get far() { + return this._far; + } + + set far(far: number) { + if (this._far !== far) { + this._far = far; + this._updateProjectionMatrix(); + } + } + + get width() { + return this._width; + } + + get height() { + return this._height; + } + + get projectionMatrix() { + return this._projectionMatrix; + } + + get viewMatrix() { + return this._viewMatrix; + } + + get viewProj() { + return this._viewProj; + } +} + +export { CameraData }; diff --git a/src/controls/FPSControls.ts b/src/controls/FPSControls.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f5d5bc3121b5e701066d73a1a15cde50cfa6902 --- /dev/null +++ b/src/controls/FPSControls.ts @@ -0,0 +1,122 @@ +import { Camera } from "../cameras/Camera"; +import { Quaternion } from "../math/Quaternion"; +import { Matrix3 } from "../math/Matrix3"; +import { Vector3 } from "../math/Vector3"; + +class FPSControls { + moveSpeed: number = 1.5; + lookSpeed: number = 0.7; + dampening: number = 0.5; + update: () => void; + dispose: () => void; + + constructor(camera: Camera, canvas: HTMLCanvasElement) { + const keys: { [key: string]: boolean } = {}; + let pitch = camera.rotation.toEuler().x; + let yaw = camera.rotation.toEuler().y; + let targetPosition = camera.position; + let pointerLock = false; + + const onMouseDown = () => { + canvas.requestPointerLock(); + }; + + const onPointerLockChange = () => { + pointerLock = document.pointerLockElement === canvas; + if (pointerLock) { + canvas.addEventListener("mousemove", onMouseMove); + } else { + canvas.removeEventListener("mousemove", onMouseMove); + } + }; + + const onMouseMove = (e: MouseEvent) => { + const mouseX = e.movementX; + const mouseY = e.movementY; + + yaw += mouseX * this.lookSpeed * 0.001; + pitch -= mouseY * this.lookSpeed * 0.001; + pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch)); + }; + + const onKeyDown = (e: KeyboardEvent) => { + keys[e.code] = true; + // Map arrow keys to WASD keys + if (e.code === "ArrowUp") keys["KeyW"] = true; + if (e.code === "ArrowDown") keys["KeyS"] = true; + if (e.code === "ArrowLeft") keys["KeyA"] = true; + if (e.code === "ArrowRight") keys["KeyD"] = true; + }; + + const onKeyUp = (e: KeyboardEvent) => { + keys[e.code] = false; + // Map arrow keys to WASD keys + if (e.code === "ArrowUp") keys["KeyW"] = false; + if (e.code === "ArrowDown") keys["KeyS"] = false; + if (e.code === "ArrowLeft") keys["KeyA"] = false; + if (e.code === "ArrowRight") keys["KeyD"] = false; + if (e.code === "Escape") document.exitPointerLock(); + }; + + this.update = () => { + const R = Matrix3.RotationFromQuaternion(camera.rotation).buffer; + const forward = new Vector3(-R[2], -R[5], -R[8]); + const right = new Vector3(R[0], R[3], R[6]); + let move = new Vector3(0, 0, 0); + if (keys["KeyS"]) { + move = move.add(forward); + } + if (keys["KeyW"]) { + move = move.subtract(forward); + } + if (keys["KeyA"]) { + move = move.subtract(right); + } + if (keys["KeyD"]) { + move = move.add(right); + } + move = new Vector3(move.x, 0, move.z); + if (move.magnitude() > 0) { + move = move.normalize(); + } + + targetPosition = targetPosition.add(move.multiply(this.moveSpeed * 0.01)); + camera.position = camera.position.add(targetPosition.subtract(camera.position).multiply(this.dampening)); + + camera.rotation = Quaternion.FromEuler(new Vector3(pitch, yaw, 0)); + }; + + const preventDefault = (e: Event) => { + e.preventDefault(); + e.stopPropagation(); + }; + + this.dispose = () => { + canvas.removeEventListener("dragenter", preventDefault); + canvas.removeEventListener("dragover", preventDefault); + canvas.removeEventListener("dragleave", preventDefault); + canvas.removeEventListener("contextmenu", preventDefault); + canvas.removeEventListener("mousedown", onMouseDown); + + document.removeEventListener("pointerlockchange", onPointerLockChange); + + window.removeEventListener("keydown", onKeyDown); + window.removeEventListener("keyup", onKeyUp); + }; + + window.addEventListener("keydown", onKeyDown); + window.addEventListener("keyup", onKeyUp); + + canvas.addEventListener("dragenter", preventDefault); + canvas.addEventListener("dragover", preventDefault); + canvas.addEventListener("dragleave", preventDefault); + canvas.addEventListener("contextmenu", preventDefault); + canvas.addEventListener("mousedown", onMouseDown); + + document.addEventListener("pointerlockchange", onPointerLockChange); + + this.update(); + } +} + +export { FPSControls }; diff --git a/src/controls/OrbitControls.ts b/src/controls/OrbitControls.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e1993481c738b59f7bcac5cc0ba5318ddc517d5 --- /dev/null +++ b/src/controls/OrbitControls.ts @@ -0,0 +1,310 @@ +import { Camera } from "../cameras/Camera"; +import { Matrix3 } from "../math/Matrix3"; +import { Quaternion } from "../math/Quaternion"; +import { Vector3 } from "../math/Vector3"; + +class OrbitControls { + minAngle: number = -90; + maxAngle: number = 90; + minZoom: number = 0.1; + maxZoom: number = 30; + orbitSpeed: number = 1; + panSpeed: number = 1; + zoomSpeed: number = 1; + dampening: number = 0.12; + setCameraTarget: (newTarget: Vector3) => void = () => {}; + update: () => void; + dispose: () => void; + + constructor( + camera: Camera, + canvas: HTMLElement, + alpha: number = 0.5, + beta: number = 0.5, + radius: number = 5, + enableKeyboardControls: boolean = true, + inputTarget: Vector3 = new Vector3(), + ) { + let target = inputTarget.clone(); + + let desiredTarget = target.clone(); + let desiredAlpha = alpha; + let desiredBeta = beta; + let desiredRadius = radius; + + let dragging = false; + let panning = false; + let lastDist = 0; + let lastX = 0; + let lastY = 0; + + const keys: { [key: string]: boolean } = {}; + + let isUpdatingCamera = false; + + const onCameraChange = () => { + if (isUpdatingCamera) return; + + const eulerRotation = camera.rotation.toEuler(); + desiredAlpha = -eulerRotation.y; + desiredBeta = -eulerRotation.x; + + const x = camera.position.x - desiredRadius * Math.sin(desiredAlpha) * Math.cos(desiredBeta); + const y = camera.position.y + desiredRadius * Math.sin(desiredBeta); + const z = camera.position.z + desiredRadius * Math.cos(desiredAlpha) * Math.cos(desiredBeta); + + desiredTarget = new Vector3(x, y, z); + }; + + camera.addEventListener("objectChanged", onCameraChange); + + this.setCameraTarget = (newTarget: Vector3) => { + const dx = newTarget.x - camera.position.x; + const dy = newTarget.y - camera.position.y; + const dz = newTarget.z - camera.position.z; + desiredRadius = Math.sqrt(dx * dx + dy * dy + dz * dz); + desiredBeta = Math.atan2(dy, Math.sqrt(dx * dx + dz * dz)); + desiredAlpha = -Math.atan2(dx, dz); + desiredTarget = new Vector3(newTarget.x, newTarget.y, newTarget.z); + }; + + const computeZoomNorm = () => { + return 0.1 + (0.9 * (desiredRadius - this.minZoom)) / (this.maxZoom - this.minZoom); + }; + + const onKeyDown = (e: KeyboardEvent) => { + keys[e.code] = true; + // Map arrow keys to WASD keys + if (e.code === "ArrowUp") keys["KeyW"] = true; + if (e.code === "ArrowDown") keys["KeyS"] = true; + if (e.code === "ArrowLeft") keys["KeyA"] = true; + if (e.code === "ArrowRight") keys["KeyD"] = true; + }; + + const onKeyUp = (e: KeyboardEvent) => { + keys[e.code] = false; // Map arrow keys to WASD keys + if (e.code === "ArrowUp") keys["KeyW"] = false; + if (e.code === "ArrowDown") keys["KeyS"] = false; + if (e.code === "ArrowLeft") keys["KeyA"] = false; + if (e.code === "ArrowRight") keys["KeyD"] = false; + }; + + const onMouseDown = (e: MouseEvent) => { + preventDefault(e); + + dragging = true; + panning = e.button === 2; + lastX = e.clientX; + lastY = e.clientY; + window.addEventListener("mouseup", onMouseUp); + }; + + const onMouseUp = (e: MouseEvent) => { + preventDefault(e); + + dragging = false; + panning = false; + window.removeEventListener("mouseup", onMouseUp); + }; + + const onMouseMove = (e: MouseEvent) => { + preventDefault(e); + + if (!dragging || !camera) return; + + const dx = e.clientX - lastX; + const dy = e.clientY - lastY; + + if (panning) { + const zoomNorm = computeZoomNorm(); + const panX = -dx * this.panSpeed * 0.01 * zoomNorm; + const panY = -dy * this.panSpeed * 0.01 * zoomNorm; + const R = Matrix3.RotationFromQuaternion(camera.rotation).buffer; + const right = new Vector3(R[0], R[3], R[6]); + const up = new Vector3(R[1], R[4], R[7]); + desiredTarget = desiredTarget.add(right.multiply(panX)); + desiredTarget = desiredTarget.add(up.multiply(panY)); + } else { + desiredAlpha -= dx * this.orbitSpeed * 0.003; + desiredBeta += dy * this.orbitSpeed * 0.003; + desiredBeta = Math.min( + Math.max(desiredBeta, (this.minAngle * Math.PI) / 180), + (this.maxAngle * Math.PI) / 180, + ); + } + + lastX = e.clientX; + lastY = e.clientY; + }; + + const onWheel = (e: WheelEvent) => { + preventDefault(e); + + const zoomNorm = computeZoomNorm(); + desiredRadius += e.deltaY * this.zoomSpeed * 0.025 * zoomNorm; + desiredRadius = Math.min(Math.max(desiredRadius, this.minZoom), this.maxZoom); + }; + + const onTouchStart = (e: TouchEvent) => { + preventDefault(e); + + if (e.touches.length === 1) { + dragging = true; + panning = false; + lastX = e.touches[0].clientX; + lastY = e.touches[0].clientY; + lastDist = 0; + } else if (e.touches.length === 2) { + dragging = true; + panning = true; + lastX = (e.touches[0].clientX + e.touches[1].clientX) / 2; + lastY = (e.touches[0].clientY + e.touches[1].clientY) / 2; + const distX = e.touches[0].clientX - e.touches[1].clientX; + const distY = e.touches[0].clientY - e.touches[1].clientY; + lastDist = Math.sqrt(distX * distX + distY * distY); + } + }; + + const onTouchEnd = (e: TouchEvent) => { + preventDefault(e); + + dragging = false; + panning = false; + }; + + const onTouchMove = (e: TouchEvent) => { + preventDefault(e); + + if (!dragging || !camera) return; + + if (panning) { + const zoomNorm = computeZoomNorm(); + + const distX = e.touches[0].clientX - e.touches[1].clientX; + const distY = e.touches[0].clientY - e.touches[1].clientY; + const dist = Math.sqrt(distX * distX + distY * distY); + const delta = lastDist - dist; + desiredRadius += delta * this.zoomSpeed * 0.1 * zoomNorm; + desiredRadius = Math.min(Math.max(desiredRadius, this.minZoom), this.maxZoom); + lastDist = dist; + + const touchX = (e.touches[0].clientX + e.touches[1].clientX) / 2; + const touchY = (e.touches[0].clientY + e.touches[1].clientY) / 2; + const dx = touchX - lastX; + const dy = touchY - lastY; + const R = Matrix3.RotationFromQuaternion(camera.rotation).buffer; + const right = new Vector3(R[0], R[3], R[6]); + const up = new Vector3(R[1], R[4], R[7]); + desiredTarget = desiredTarget.add(right.multiply(-dx * this.panSpeed * 0.025 * zoomNorm)); + desiredTarget = desiredTarget.add(up.multiply(-dy * this.panSpeed * 0.025 * zoomNorm)); + lastX = touchX; + lastY = touchY; + } else { + const dx = e.touches[0].clientX - lastX; + const dy = e.touches[0].clientY - lastY; + + desiredAlpha -= dx * this.orbitSpeed * 0.003; + desiredBeta += dy * this.orbitSpeed * 0.003; + desiredBeta = Math.min( + Math.max(desiredBeta, (this.minAngle * Math.PI) / 180), + (this.maxAngle * Math.PI) / 180, + ); + + lastX = e.touches[0].clientX; + lastY = e.touches[0].clientY; + } + }; + + const lerp = (a: number, b: number, t: number) => { + return (1 - t) * a + t * b; + }; + + this.update = () => { + isUpdatingCamera = true; + + alpha = lerp(alpha, desiredAlpha, this.dampening); + beta = lerp(beta, desiredBeta, this.dampening); + radius = lerp(radius, desiredRadius, this.dampening); + target = target.lerp(desiredTarget, this.dampening); + + const x = target.x + radius * Math.sin(alpha) * Math.cos(beta); + const y = target.y - radius * Math.sin(beta); + const z = target.z - radius * Math.cos(alpha) * Math.cos(beta); + camera.position = new Vector3(x, y, z); + + const direction = target.subtract(camera.position).normalize(); + const rx = Math.asin(-direction.y); + const ry = Math.atan2(direction.x, direction.z); + camera.rotation = Quaternion.FromEuler(new Vector3(rx, ry, 0)); + + const moveSpeed = 0.025; + const rotateSpeed = 0.01; + + const R = Matrix3.RotationFromQuaternion(camera.rotation).buffer; + const forward = new Vector3(-R[2], -R[5], -R[8]); + const right = new Vector3(R[0], R[3], R[6]); + + if (keys["KeyS"]) desiredTarget = desiredTarget.add(forward.multiply(moveSpeed)); + if (keys["KeyW"]) desiredTarget = desiredTarget.subtract(forward.multiply(moveSpeed)); + if (keys["KeyA"]) desiredTarget = desiredTarget.subtract(right.multiply(moveSpeed)); + if (keys["KeyD"]) desiredTarget = desiredTarget.add(right.multiply(moveSpeed)); + + // Add rotation with 'e' and 'q' for horizontal rotation + if (keys["KeyE"]) desiredAlpha += rotateSpeed; + if (keys["KeyQ"]) desiredAlpha -= rotateSpeed; + + // Add rotation with 'r' and 'f' for vertical rotation + if (keys["KeyR"]) desiredBeta += rotateSpeed; + if (keys["KeyF"]) desiredBeta -= rotateSpeed; + + isUpdatingCamera = false; + }; + + const preventDefault = (e: Event) => { + e.preventDefault(); + e.stopPropagation(); + }; + + this.dispose = () => { + canvas.removeEventListener("dragenter", preventDefault); + canvas.removeEventListener("dragover", preventDefault); + canvas.removeEventListener("dragleave", preventDefault); + canvas.removeEventListener("contextmenu", preventDefault); + + canvas.removeEventListener("mousedown", onMouseDown); + canvas.removeEventListener("mousemove", onMouseMove); + canvas.removeEventListener("wheel", onWheel); + + canvas.removeEventListener("touchstart", onTouchStart); + canvas.removeEventListener("touchend", onTouchEnd); + canvas.removeEventListener("touchmove", onTouchMove); + + if (enableKeyboardControls) { + window.removeEventListener("keydown", onKeyDown); + window.removeEventListener("keyup", onKeyUp); + } + }; + + if (enableKeyboardControls) { + window.addEventListener("keydown", onKeyDown); + window.addEventListener("keyup", onKeyUp); + } + + canvas.addEventListener("dragenter", preventDefault); + canvas.addEventListener("dragover", preventDefault); + canvas.addEventListener("dragleave", preventDefault); + canvas.addEventListener("contextmenu", preventDefault); + + canvas.addEventListener("mousedown", onMouseDown); + canvas.addEventListener("mousemove", onMouseMove); + canvas.addEventListener("wheel", onWheel); + + canvas.addEventListener("touchstart", onTouchStart); + canvas.addEventListener("touchend", onTouchEnd); + canvas.addEventListener("touchmove", onTouchMove); + + this.update(); + } +} + +export { OrbitControls }; diff --git a/src/core/Object3D.ts b/src/core/Object3D.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0da23d369653177727160f0a56e1b03688b79e3 --- /dev/null +++ b/src/core/Object3D.ts @@ -0,0 +1,101 @@ +import { Vector3 } from "../math/Vector3"; +import { Quaternion } from "../math/Quaternion"; +import { EventDispatcher } from "../events/EventDispatcher"; +import { Matrix4 } from "../math/Matrix4"; +import { ObjectChangedEvent } from "../events/Events"; + +abstract class Object3D extends EventDispatcher { + public positionChanged: boolean = false; + public rotationChanged: boolean = false; + public scaleChanged: boolean = false; + + protected _position: Vector3 = new Vector3(); + protected _rotation: Quaternion = new Quaternion(); + protected _scale: Vector3 = new Vector3(1, 1, 1); + protected _transform: Matrix4 = new Matrix4(); + + protected _changeEvent = new ObjectChangedEvent(this); + + update: () => void; + applyPosition: () => void; + applyRotation: () => void; + applyScale: () => void; + raiseChangeEvent: () => void; + + constructor() { + super(); + + this.update = () => {}; + + this.applyPosition = () => { + this.position = new Vector3(); + }; + + this.applyRotation = () => { + this.rotation = new Quaternion(); + }; + + this.applyScale = () => { + this.scale = new Vector3(1, 1, 1); + }; + + this.raiseChangeEvent = () => { + this.dispatchEvent(this._changeEvent); + }; + } + + protected _updateMatrix() { + this._transform = Matrix4.Compose(this._position, this._rotation, this._scale); + } + + get position() { + return this._position; + } + + set position(position: Vector3) { + if (!this._position.equals(position)) { + this._position = position; + this.positionChanged = true; + this._updateMatrix(); + this.dispatchEvent(this._changeEvent); + } + } + + get rotation() { + return this._rotation; + } + + set rotation(rotation: Quaternion) { + if (!this._rotation.equals(rotation)) { + this._rotation = rotation; + this.rotationChanged = true; + this._updateMatrix(); + this.dispatchEvent(this._changeEvent); + } + } + + get scale() { + return this._scale; + } + + set scale(scale: Vector3) { + if (!this._scale.equals(scale)) { + this._scale = scale; + this.scaleChanged = true; + this._updateMatrix(); + this.dispatchEvent(this._changeEvent); + } + } + + get forward() { + let forward = new Vector3(0, 0, 1); + forward = this.rotation.apply(forward); + return forward; + } + + get transform() { + return this._transform; + } +} + +export { Object3D }; diff --git a/src/core/Scene.ts b/src/core/Scene.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ee44bb75eb23fddbaa0e330298a5f29b67ecba8 --- /dev/null +++ b/src/core/Scene.ts @@ -0,0 +1,117 @@ +import { Object3D } from "./Object3D"; +import { SplatData } from "../splats/SplatData"; +import { Splat } from "../splats/Splat"; +import { EventDispatcher } from "../events/EventDispatcher"; +import { ObjectAddedEvent, ObjectRemovedEvent } from "../events/Events"; +import { Converter } from "../utils/Converter"; + +class Scene extends EventDispatcher { + private _objects: Object3D[] = []; + + addObject: (object: Object3D) => void; + removeObject: (object: Object3D) => void; + findObject: (predicate: (object: Object3D) => boolean) => Object3D | undefined; + findObjectOfType: (type: { new (): T }) => T | undefined; + reset: () => void; + + constructor() { + super(); + + this.addObject = (object: Object3D) => { + this.objects.push(object); + this.dispatchEvent(new ObjectAddedEvent(object)); + }; + + this.removeObject = (object: Object3D) => { + const index = this.objects.indexOf(object); + if (index < 0) { + throw new Error("Object not found in scene"); + } + this.objects.splice(index, 1); + this.dispatchEvent(new ObjectRemovedEvent(object)); + }; + + this.findObject = (predicate: (object: Object3D) => boolean) => { + for (const object of this.objects) { + if (predicate(object)) { + return object; + } + } + return undefined; + }; + + this.findObjectOfType = (type: { new (): T }) => { + for (const object of this.objects) { + if (object instanceof type) { + return object; + } + } + return undefined; + }; + + this.reset = () => { + const objectsToRemove = this.objects.slice(); + for (const object of objectsToRemove) { + this.removeObject(object); + } + }; + + this.reset(); + } + + getMergedSceneDataBuffer(format: "splat" | "ply" = "splat"): ArrayBuffer { + const buffers: Uint8Array[] = []; + let vertexCount = 0; + + for (const object of this.objects) { + if (object instanceof Splat) { + const splatClone = object.clone() as Splat; + + splatClone.applyRotation(); + splatClone.applyScale(); + splatClone.applyPosition(); + const buffer = splatClone.data.serialize(); + + buffers.push(buffer); + vertexCount += splatClone.data.vertexCount; + } + } + + const mergedSplatData = new Uint8Array(vertexCount * SplatData.RowLength); + let offset = 0; + for (const buffer of buffers) { + mergedSplatData.set(buffer, offset); + offset += buffer.length; + } + + if (format === "ply") { + return Converter.SplatToPLY(mergedSplatData.buffer, vertexCount); + } + + return mergedSplatData.buffer; + } + + saveToFile(name: string | null = null, format: "splat" | "ply" = "splat") { + if (!document) return; + + if (!name) { + const now = new Date(); + name = `scene-${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}.${format}`; + } + + const mergedData = this.getMergedSceneDataBuffer(format); + + const blob = new Blob([mergedData], { type: "application/octet-stream" }); + + const link = document.createElement("a"); + link.download = name; + link.href = URL.createObjectURL(blob); + link.click(); + } + + get objects() { + return this._objects; + } +} + +export { Scene }; diff --git a/src/custom.d.ts b/src/custom.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3d72f1b6d9deface6c3bc0996b643169a231a80 --- /dev/null +++ b/src/custom.d.ts @@ -0,0 +1,6 @@ +declare module "web-worker:*" { + const WorkerConstructor: { + new (): Worker; + }; + export default WorkerConstructor; +} diff --git a/src/events/EventDispatcher.ts b/src/events/EventDispatcher.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5467e144f1ccb675b6e7a3d0c29237acd836f66 --- /dev/null +++ b/src/events/EventDispatcher.ts @@ -0,0 +1,46 @@ +class EventDispatcher { + addEventListener: (type: string, listener: (event: Event) => void) => void; + removeEventListener: (type: string, listener: (event: Event) => void) => void; + hasEventListener: (type: string, listener: (event: Event) => void) => boolean; + dispatchEvent: (event: Event) => void; + + constructor() { + const listeners = new Map void>>(); + + this.addEventListener = (type: string, listener: (event: Event) => void) => { + if (!listeners.has(type)) { + listeners.set(type, new Set()); + } + + listeners.get(type)!.add(listener); + }; + + this.removeEventListener = (type: string, listener: (event: Event) => void) => { + if (!listeners.has(type)) { + return; + } + + listeners.get(type)!.delete(listener); + }; + + this.hasEventListener = (type: string, listener: (event: Event) => void) => { + if (!listeners.has(type)) { + return false; + } + + return listeners.get(type)!.has(listener); + }; + + this.dispatchEvent = (event: Event) => { + if (!listeners.has(event.type)) { + return; + } + + for (const listener of listeners.get(event.type)!) { + listener(event); + } + }; + } +} + +export { EventDispatcher }; diff --git a/src/events/Events.ts b/src/events/Events.ts new file mode 100644 index 0000000000000000000000000000000000000000..d521bf6e4235d6b40f609bf6b33c391d8a880f0c --- /dev/null +++ b/src/events/Events.ts @@ -0,0 +1,21 @@ +import { Object3D } from "../core/Object3D"; + +class ObjectAddedEvent extends Event { + constructor(public object: Object3D) { + super("objectAdded"); + } +} + +class ObjectRemovedEvent extends Event { + constructor(public object: Object3D) { + super("objectRemoved"); + } +} + +class ObjectChangedEvent extends Event { + constructor(public object: Object3D) { + super("objectChanged"); + } +} + +export { ObjectAddedEvent, ObjectRemovedEvent, ObjectChangedEvent }; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ca495a68844e8b6f928b5db03a1e6bb4a8357ce --- /dev/null +++ b/src/index.ts @@ -0,0 +1,28 @@ +export { Object3D } from "./core/Object3D"; +export { SplatData } from "./splats/SplatData"; +export { SplatvData } from "./splats/SplatvData"; +export { Splat } from "./splats/Splat"; +export { Splatv } from "./splats/Splatv"; +export { CameraData } from "./cameras/CameraData"; +export { Camera } from "./cameras/Camera"; +export { Scene } from "./core/Scene"; +export { Loader } from "./loaders/Loader"; +export { PLYLoader } from "./loaders/PLYLoader"; +export { SplatvLoader } from "./loaders/SplatvLoader"; +export { WebGLRenderer } from "./renderers/WebGLRenderer"; +export { OrbitControls } from "./controls/OrbitControls"; +export { FPSControls } from "./controls/FPSControls"; +export { Quaternion } from "./math/Quaternion"; +export { Vector3 } from "./math/Vector3"; +export { Vector4 } from "./math/Vector4"; +export { Matrix4 } from "./math/Matrix4"; +export { Matrix3 } from "./math/Matrix3"; +export { Color32 } from "./math/Color32"; +export { Plane } from "./math/Plane"; +export { ShaderPass } from "./renderers/webgl/passes/ShaderPass"; +export { FadeInPass } from "./renderers/webgl/passes/FadeInPass"; +export { RenderData } from "./renderers/webgl/utils/RenderData"; +export { ShaderProgram } from "./renderers/webgl/programs/ShaderProgram"; +export { RenderProgram } from "./renderers/webgl/programs/RenderProgram"; +export { VideoRenderProgram } from "./renderers/webgl/programs/VideoRenderProgram"; +export { IntersectionTester } from "./renderers/webgl/utils/IntersectionTester"; diff --git a/src/loaders/Loader.ts b/src/loaders/Loader.ts new file mode 100644 index 0000000000000000000000000000000000000000..82a1d74df7566bd04b292196f0d96dc76b46255d --- /dev/null +++ b/src/loaders/Loader.ts @@ -0,0 +1,46 @@ +import type { Scene } from "../core/Scene"; +import { Splat } from "../splats/Splat"; +import { SplatData } from "../splats/SplatData"; +import { initiateFetchRequest, loadRequestDataIntoBuffer } from "../utils/LoaderUtils"; + +class Loader { + static async LoadAsync( + url: string, + scene: Scene, + onProgress?: (progress: number) => void, + useCache: boolean = false, + ): Promise { + const res: Response = await initiateFetchRequest(url, useCache); + + const buffer = await loadRequestDataIntoBuffer(res, onProgress); + return this.LoadFromArrayBuffer(buffer, scene); + } + + static async LoadFromFileAsync(file: File, scene: Scene, onProgress?: (progress: number) => void): Promise { + const reader = new FileReader(); + let splat = new Splat(); + reader.onload = (e) => { + splat = this.LoadFromArrayBuffer(e.target!.result as ArrayBuffer, scene); + }; + reader.onprogress = (e) => { + onProgress?.(e.loaded / e.total); + }; + reader.readAsArrayBuffer(file); + await new Promise((resolve) => { + reader.onloadend = () => { + resolve(); + }; + }); + return splat; + } + + static LoadFromArrayBuffer(arrayBuffer: ArrayBufferLike, scene: Scene): Splat { + const buffer = new Uint8Array(arrayBuffer); + const data = SplatData.Deserialize(buffer); + const splat = new Splat(data); + scene.addObject(splat); + return splat; + } +} + +export { Loader }; diff --git a/src/loaders/PLYLoader.ts b/src/loaders/PLYLoader.ts new file mode 100644 index 0000000000000000000000000000000000000000..1995dce6711269b9da535f3dd358c71b056afde1 --- /dev/null +++ b/src/loaders/PLYLoader.ts @@ -0,0 +1,223 @@ +import { Scene } from "../core/Scene"; +import { Vector3 } from "../math/Vector3"; +import { Quaternion } from "../math/Quaternion"; +import { SplatData } from "../splats/SplatData"; +import { Splat } from "../splats/Splat"; +import { Converter } from "../utils/Converter"; +import { initiateFetchRequest, loadRequestDataIntoBuffer } from "../utils/LoaderUtils"; + +class PLYLoader { + static async LoadAsync( + url: string, + scene: Scene, + onProgress?: (progress: number) => void, + format: string = "", + useCache: boolean = false, + ): Promise { + const res: Response = await initiateFetchRequest(url, useCache); + + const plyData = await loadRequestDataIntoBuffer(res, onProgress); + + if (plyData[0] !== 112 || plyData[1] !== 108 || plyData[2] !== 121 || plyData[3] !== 10) { + throw new Error("Invalid PLY file"); + } + + return this.LoadFromArrayBuffer(plyData.buffer, scene, format); + } + + static async LoadFromFileAsync( + file: File, + scene: Scene, + onProgress?: (progress: number) => void, + format: string = "", + ): Promise { + const reader = new FileReader(); + let splat = new Splat(); + reader.onload = (e) => { + splat = this.LoadFromArrayBuffer(e.target!.result as ArrayBuffer, scene, format); + }; + reader.onprogress = (e) => { + onProgress?.(e.loaded / e.total); + }; + reader.readAsArrayBuffer(file); + await new Promise((resolve) => { + reader.onloadend = () => { + resolve(); + }; + }); + return splat; + } + + static LoadFromArrayBuffer(arrayBuffer: ArrayBufferLike, scene: Scene, format: string = ""): Splat { + const buffer = new Uint8Array(this._ParsePLYBuffer(arrayBuffer, format)); + const data = SplatData.Deserialize(buffer); + const splat = new Splat(data); + scene.addObject(splat); + return splat; + } + + private static _ParsePLYBuffer(inputBuffer: ArrayBuffer, format: string): ArrayBuffer { + type PlyProperty = { + name: string; + type: string; + offset: number; + }; + + const ubuf = new Uint8Array(inputBuffer); + const headerText = new TextDecoder().decode(ubuf.slice(0, 1024 * 10)); + const header_end = "end_header\n"; + const header_end_index = headerText.indexOf(header_end); + if (header_end_index < 0) throw new Error("Unable to read .ply file header"); + + const vertexCount = parseInt(/element vertex (\d+)\n/.exec(headerText)![1]); + + let rowOffset = 0; + const offsets: Record = { + double: 8, + int: 4, + uint: 4, + float: 4, + short: 2, + ushort: 2, + uchar: 1, + }; + + const properties: PlyProperty[] = []; + for (const prop of headerText + .slice(0, header_end_index) + .split("\n") + .filter((k) => k.startsWith("property "))) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_p, type, name] = prop.split(" "); + properties.push({ name, type, offset: rowOffset }); + + if (!offsets[type]) throw new Error(`Unsupported property type: ${type}`); + rowOffset += offsets[type]; + } + + const dataView = new DataView(inputBuffer, header_end_index + header_end.length); + const buffer = new ArrayBuffer(SplatData.RowLength * vertexCount); + + const q_polycam = Quaternion.FromEuler(new Vector3(Math.PI / 2, 0, 0)); + + for (let i = 0; i < vertexCount; i++) { + const position = new Float32Array(buffer, i * SplatData.RowLength, 3); + const scale = new Float32Array(buffer, i * SplatData.RowLength + 12, 3); + const rgba = new Uint8ClampedArray(buffer, i * SplatData.RowLength + 24, 4); + const rot = new Uint8ClampedArray(buffer, i * SplatData.RowLength + 28, 4); + + let r0: number = 255; + let r1: number = 0; + let r2: number = 0; + let r3: number = 0; + + properties.forEach((property) => { + let value; + switch (property.type) { + case "float": + value = dataView.getFloat32(property.offset + i * rowOffset, true); + break; + case "int": + value = dataView.getInt32(property.offset + i * rowOffset, true); + break; + default: + throw new Error(`Unsupported property type: ${property.type}`); + } + + switch (property.name) { + case "x": + position[0] = value; + break; + case "y": + position[1] = value; + break; + case "z": + position[2] = value; + break; + case "scale_0": + case "scaling_0": + scale[0] = Math.exp(value); + break; + case "scale_1": + case "scaling_1": + scale[1] = Math.exp(value); + break; + case "scale_2": + case "scaling_2": + scale[2] = Math.exp(value); + break; + case "red": + rgba[0] = value; + break; + case "green": + rgba[1] = value; + break; + case "blue": + rgba[2] = value; + break; + case "f_dc_0": + case "features_0": + rgba[0] = (0.5 + Converter.SH_C0 * value) * 255; + break; + case "f_dc_1": + case "features_1": + rgba[1] = (0.5 + Converter.SH_C0 * value) * 255; + break; + case "f_dc_2": + case "features_2": + rgba[2] = (0.5 + Converter.SH_C0 * value) * 255; + break; + case "f_dc_3": + rgba[3] = (0.5 + Converter.SH_C0 * value) * 255; + break; + case "opacity": + case "opacity_0": + rgba[3] = (1 / (1 + Math.exp(-value))) * 255; + break; + case "rot_0": + case "rotation_0": + r0 = value; + break; + case "rot_1": + case "rotation_1": + r1 = value; + break; + case "rot_2": + case "rotation_2": + r2 = value; + break; + case "rot_3": + case "rotation_3": + r3 = value; + break; + } + }); + + let q = new Quaternion(r1, r2, r3, r0); + + switch (format) { + case "polycam": { + const temp = position[1]; + position[1] = -position[2]; + position[2] = temp; + q = q_polycam.multiply(q); + break; + } + case "": + break; + default: + throw new Error(`Unsupported format: ${format}`); + } + + q = q.normalize(); + rot[0] = q.w * 128 + 128; + rot[1] = q.x * 128 + 128; + rot[2] = q.y * 128 + 128; + rot[3] = q.z * 128 + 128; + } + + return buffer; + } +} + +export { PLYLoader }; diff --git a/src/loaders/SplatvLoader.ts b/src/loaders/SplatvLoader.ts new file mode 100644 index 0000000000000000000000000000000000000000..51eb36708c9c710fd65d5145a3bc5c96f3ca35b2 --- /dev/null +++ b/src/loaders/SplatvLoader.ts @@ -0,0 +1,135 @@ +import { Camera } from "../cameras/Camera"; +import type { Scene } from "../core/Scene"; +import { Matrix3 } from "../math/Matrix3"; +import { Quaternion } from "../math/Quaternion"; +import { Vector3 } from "../math/Vector3"; +import { Splatv } from "../splats/Splatv"; +import { SplatvData } from "../splats/SplatvData"; +import { initiateFetchRequest, loadRequestDataIntoBuffer } from "../utils/LoaderUtils"; + +class SplatvLoader { + static async LoadAsync( + url: string, + scene: Scene, + camera: Camera | null, + onProgress?: (progress: number) => void, + useCache: boolean = false, + ): Promise { + const res: Response = await initiateFetchRequest(url, useCache); + + const buffer = await loadRequestDataIntoBuffer(res, onProgress); + return this._ParseSplatvBuffer(buffer.buffer, scene, camera); + } + + static async LoadFromFileAsync( + file: File, + scene: Scene, + camera: Camera | null, + onProgress?: (progress: number) => void, + ): Promise { + const reader = new FileReader(); + let splatv: Splatv | null = null; + reader.onload = (e) => { + splatv = this._ParseSplatvBuffer(e.target!.result as ArrayBuffer, scene, camera); + }; + reader.onprogress = (e) => { + onProgress?.(e.loaded / e.total); + }; + reader.readAsArrayBuffer(file); + await new Promise((resolve) => { + reader.onloadend = () => { + resolve(); + }; + }); + if (!splatv) { + throw new Error("Failed to load splatv file"); + } + return splatv; + } + + private static _ParseSplatvBuffer(inputBuffer: ArrayBuffer, scene: Scene, camera: Camera | null): Splatv { + let result: Splatv | null = null; + + const handleChunk = ( + chunk: { size: number; type: string; texwidth: number; texheight: number }, + buffer: Uint8Array, + chunks: { size: number; type: string }[], + ) => { + if (chunk.type === "magic") { + const intView = new Int32Array(buffer.buffer); + if (intView[0] !== 0x674b) { + throw new Error("Invalid splatv file"); + } + chunks.push({ size: intView[1], type: "chunks" }); + } else if (chunk.type === "chunks") { + const splatChunks = JSON.parse(new TextDecoder("utf-8").decode(buffer)); + if (splatChunks.length == 0) { + throw new Error("Invalid splatv file"); + } else if (splatChunks.length > 1) { + console.warn("Splatv file contains more than one chunk, only the first one will be loaded"); + } + const chunk = splatChunks[0]; + const cameras = chunk.cameras as { position: number[]; rotation: number[][] }[]; + if (camera && cameras && cameras.length) { + const cameraData = cameras[0]; + const position = new Vector3( + cameraData.position[0], + cameraData.position[1], + cameraData.position[2], + ); + const rotation = Quaternion.FromMatrix3( + new Matrix3( + cameraData.rotation[0][0], + cameraData.rotation[0][1], + cameraData.rotation[0][2], + cameraData.rotation[1][0], + cameraData.rotation[1][1], + cameraData.rotation[1][2], + cameraData.rotation[2][0], + cameraData.rotation[2][1], + cameraData.rotation[2][2], + ), + ); + camera.position = position; + camera.rotation = rotation; + } + chunks.push(chunk); + } else if (chunk.type === "splat") { + const data = SplatvData.Deserialize(buffer, chunk.texwidth, chunk.texheight); + const splatv = new Splatv(data); + scene.addObject(splatv); + result = splatv; + } + }; + + const ubuf = new Uint8Array(inputBuffer); + const chunks: { size: number; type: string; texwidth: number; texheight: number }[] = [ + { size: 8, type: "magic", texwidth: 0, texheight: 0 }, + ]; + let chunk: { size: number; type: string; texwidth: number; texheight: number } | undefined = chunks.shift(); + let buffer = new Uint8Array(chunk!.size); + let offset = 0; + let inputOffset = 0; + while (chunk) { + while (offset < chunk.size) { + const sizeToRead = Math.min(chunk.size - offset, ubuf.length - inputOffset); + buffer.set(ubuf.subarray(inputOffset, inputOffset + sizeToRead), offset); + offset += sizeToRead; + inputOffset += sizeToRead; + } + handleChunk(chunk, buffer, chunks); + if (result) { + return result; + } + chunk = chunks.shift(); + if (chunk) { + buffer = new Uint8Array(chunk.size); + offset = 0; + } + } + + throw new Error("Invalid splatv file"); + } +} + +export { SplatvLoader }; diff --git a/src/math/BVH.ts b/src/math/BVH.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9d578e5b0a3e191141e6514111a582ac76e75e0 --- /dev/null +++ b/src/math/BVH.ts @@ -0,0 +1,56 @@ +import { Box3 } from "./Box3"; + +class BVHNode { + public left: BVHNode | null = null; + public right: BVHNode | null = null; + public pointIndices: number[] = []; + + constructor( + public bounds: Box3, + public boxes: Box3[], + pointIndices: number[], + ) { + if (pointIndices.length > 1) { + this.split(bounds, boxes, pointIndices); + } else if (pointIndices.length > 0) { + this.pointIndices = pointIndices; + } + } + + private split(bounds: Box3, boxes: Box3[], pointIndices: number[]) { + const axis = bounds.size().maxComponent(); + pointIndices.sort((a, b) => boxes[a].center().getComponent(axis) - boxes[b].center().getComponent(axis)); + + const mid = Math.floor(pointIndices.length / 2); + const leftIndices = pointIndices.slice(0, mid); + const rightIndices = pointIndices.slice(mid); + + this.left = new BVHNode(bounds, boxes, leftIndices); + this.right = new BVHNode(bounds, boxes, rightIndices); + } + + public queryRange(range: Box3): number[] { + if (!this.bounds.intersects(range)) { + return []; + } else if (this.left !== null && this.right !== null) { + return this.left.queryRange(range).concat(this.right.queryRange(range)); + } else { + return this.pointIndices.filter((index) => range.intersects(this.boxes[index])); + } + } +} + +class BVH { + public root: BVHNode; + + constructor(bounds: Box3, boxes: Box3[]) { + const pointIndices = boxes.map((_, index) => index); + this.root = new BVHNode(bounds, boxes, pointIndices); + } + + public queryRange(range: Box3) { + return this.root.queryRange(range); + } +} + +export { BVH }; diff --git a/src/math/Box3.ts b/src/math/Box3.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb1da1c4df0317db5d52b5f98224c41c2ea8c4fe --- /dev/null +++ b/src/math/Box3.ts @@ -0,0 +1,52 @@ +import { Vector3 } from "./Vector3"; + +class Box3 { + constructor( + public min: Vector3, + public max: Vector3, + ) {} + + public contains(point: Vector3) { + return ( + point.x >= this.min.x && + point.x <= this.max.x && + point.y >= this.min.y && + point.y <= this.max.y && + point.z >= this.min.z && + point.z <= this.max.z + ); + } + + public intersects(box: Box3) { + return ( + this.max.x >= box.min.x && + this.min.x <= box.max.x && + this.max.y >= box.min.y && + this.min.y <= box.max.y && + this.max.z >= box.min.z && + this.min.z <= box.max.z + ); + } + + public size() { + return this.max.subtract(this.min); + } + + public center() { + return this.min.add(this.max).divide(2); + } + + public expand(point: Vector3) { + this.min = this.min.min(point); + this.max = this.max.max(point); + } + + public permute() { + const min = this.min; + const max = this.max; + this.min = new Vector3(Math.min(min.x, max.x), Math.min(min.y, max.y), Math.min(min.z, max.z)); + this.max = new Vector3(Math.max(min.x, max.x), Math.max(min.y, max.y), Math.max(min.z, max.z)); + } +} + +export { Box3 }; diff --git a/src/math/Color32.ts b/src/math/Color32.ts new file mode 100644 index 0000000000000000000000000000000000000000..04e372080bd6d05d7cd70a042b4554ac006eec41 --- /dev/null +++ b/src/math/Color32.ts @@ -0,0 +1,36 @@ +class Color32 { + public readonly r: number; + public readonly g: number; + public readonly b: number; + public readonly a: number; + + constructor(r: number = 0, g: number = 0, b: number = 0, a: number = 255) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + flat(): number[] { + return [this.r, this.g, this.b, this.a]; + } + + flatNorm(): number[] { + return [this.r / 255, this.g / 255, this.b / 255, this.a / 255]; + } + + toHexString(): string { + return ( + "#" + + this.flat() + .map((x) => x.toString(16).padStart(2, "0")) + .join("") + ); + } + + toString(): string { + return `[${this.flat().join(", ")}]`; + } +} + +export { Color32 }; diff --git a/src/math/Matrix3.ts b/src/math/Matrix3.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ea55dfc0bf597b4712d018831e32bf8509fd653 --- /dev/null +++ b/src/math/Matrix3.ts @@ -0,0 +1,110 @@ +import { Quaternion } from "./Quaternion"; +import type { Vector3 } from "./Vector3"; + +class Matrix3 { + public readonly buffer: number[]; + + // prettier-ignore + constructor(n11: number = 1, n12: number = 0, n13: number = 0, + n21: number = 0, n22: number = 1, n23: number = 0, + n31: number = 0, n32: number = 0, n33: number = 1) { + this.buffer = [ + n11, n12, n13, + n21, n22, n23, + n31, n32, n33 + ]; + } + + equals(m: Matrix3): boolean { + if (this.buffer.length !== m.buffer.length) { + return false; + } + if (this.buffer === m.buffer) { + return true; + } + for (let i = 0; i < this.buffer.length; i++) { + if (this.buffer[i] !== m.buffer[i]) { + return false; + } + } + return true; + } + + multiply(v: Matrix3): Matrix3 { + const a = this.buffer; + const b = v.buffer; + return new Matrix3( + b[0] * a[0] + b[3] * a[1] + b[6] * a[2], + b[1] * a[0] + b[4] * a[1] + b[7] * a[2], + b[2] * a[0] + b[5] * a[1] + b[8] * a[2], + b[0] * a[3] + b[3] * a[4] + b[6] * a[5], + b[1] * a[3] + b[4] * a[4] + b[7] * a[5], + b[2] * a[3] + b[5] * a[4] + b[8] * a[5], + b[0] * a[6] + b[3] * a[7] + b[6] * a[8], + b[1] * a[6] + b[4] * a[7] + b[7] * a[8], + b[2] * a[6] + b[5] * a[7] + b[8] * a[8], + ); + } + + clone(): Matrix3 { + const e = this.buffer; + // prettier-ignore + return new Matrix3( + e[0], e[1], e[2], + e[3], e[4], e[5], + e[6], e[7], e[8] + ); + } + + static Eye(v: number = 1): Matrix3 { + return new Matrix3(v, 0, 0, 0, v, 0, 0, 0, v); + } + + static Diagonal(v: Vector3): Matrix3 { + return new Matrix3(v.x, 0, 0, 0, v.y, 0, 0, 0, v.z); + } + + static RotationFromQuaternion(q: Quaternion): Matrix3 { + const matrix = new Matrix3( + 1 - 2 * q.y * q.y - 2 * q.z * q.z, + 2 * q.x * q.y - 2 * q.z * q.w, + 2 * q.x * q.z + 2 * q.y * q.w, + 2 * q.x * q.y + 2 * q.z * q.w, + 1 - 2 * q.x * q.x - 2 * q.z * q.z, + 2 * q.y * q.z - 2 * q.x * q.w, + 2 * q.x * q.z - 2 * q.y * q.w, + 2 * q.y * q.z + 2 * q.x * q.w, + 1 - 2 * q.x * q.x - 2 * q.y * q.y, + ); + return matrix; + } + + static RotationFromEuler(m: Vector3): Matrix3 { + const cx = Math.cos(m.x); + const sx = Math.sin(m.x); + const cy = Math.cos(m.y); + const sy = Math.sin(m.y); + const cz = Math.cos(m.z); + const sz = Math.sin(m.z); + + const rotationMatrix = [ + cy * cz + sy * sx * sz, + -cy * sz + sy * sx * cz, + sy * cx, + cx * sz, + cx * cz, + -sx, + -sy * cz + cy * sx * sz, + sy * sz + cy * sx * cz, + cy * cx, + ]; + + return new Matrix3(...rotationMatrix); + } + + toString(): string { + return `[${this.buffer.join(", ")}]`; + } +} + +export { Matrix3 }; diff --git a/src/math/Matrix4.ts b/src/math/Matrix4.ts new file mode 100644 index 0000000000000000000000000000000000000000..d386dd244d64c61b2fc0eb3ca7cd006d950ffb52 --- /dev/null +++ b/src/math/Matrix4.ts @@ -0,0 +1,176 @@ +import { Quaternion } from "./Quaternion"; +import { Vector3 } from "./Vector3"; + +class Matrix4 { + public readonly buffer: number[]; + + // prettier-ignore + constructor(n11: number = 1, n12: number = 0, n13: number = 0, n14: number = 0, + n21: number = 0, n22: number = 1, n23: number = 0, n24: number = 0, + n31: number = 0, n32: number = 0, n33: number = 1, n34: number = 0, + n41: number = 0, n42: number = 0, n43: number = 0, n44: number = 1) { + this.buffer = [ + n11, n12, n13, n14, + n21, n22, n23, n24, + n31, n32, n33, n34, + n41, n42, n43, n44 + ]; + } + + equals(m: Matrix4): boolean { + if (this.buffer.length !== m.buffer.length) { + return false; + } + if (this.buffer === m.buffer) { + return true; + } + for (let i = 0; i < this.buffer.length; i++) { + if (this.buffer[i] !== m.buffer[i]) { + return false; + } + } + return true; + } + + multiply(m: Matrix4): Matrix4 { + const a = this.buffer; + const b = m.buffer; + return new Matrix4( + b[0] * a[0] + b[1] * a[4] + b[2] * a[8] + b[3] * a[12], + b[0] * a[1] + b[1] * a[5] + b[2] * a[9] + b[3] * a[13], + b[0] * a[2] + b[1] * a[6] + b[2] * a[10] + b[3] * a[14], + b[0] * a[3] + b[1] * a[7] + b[2] * a[11] + b[3] * a[15], + b[4] * a[0] + b[5] * a[4] + b[6] * a[8] + b[7] * a[12], + b[4] * a[1] + b[5] * a[5] + b[6] * a[9] + b[7] * a[13], + b[4] * a[2] + b[5] * a[6] + b[6] * a[10] + b[7] * a[14], + b[4] * a[3] + b[5] * a[7] + b[6] * a[11] + b[7] * a[15], + b[8] * a[0] + b[9] * a[4] + b[10] * a[8] + b[11] * a[12], + b[8] * a[1] + b[9] * a[5] + b[10] * a[9] + b[11] * a[13], + b[8] * a[2] + b[9] * a[6] + b[10] * a[10] + b[11] * a[14], + b[8] * a[3] + b[9] * a[7] + b[10] * a[11] + b[11] * a[15], + b[12] * a[0] + b[13] * a[4] + b[14] * a[8] + b[15] * a[12], + b[12] * a[1] + b[13] * a[5] + b[14] * a[9] + b[15] * a[13], + b[12] * a[2] + b[13] * a[6] + b[14] * a[10] + b[15] * a[14], + b[12] * a[3] + b[13] * a[7] + b[14] * a[11] + b[15] * a[15], + ); + } + + clone(): Matrix4 { + const e = this.buffer; + // prettier-ignore + return new Matrix4( + e[0], e[1], e[2], e[3], + e[4], e[5], e[6], e[7], + e[8], e[9], e[10], e[11], + e[12], e[13], e[14], e[15] + ); + } + + determinant(): number { + const e = this.buffer; + // prettier-ignore + return ( + e[12] * e[9] * e[6] * e[3] - e[8] * e[13] * e[6] * e[3] - e[12] * e[5] * e[10] * e[3] + e[4] * e[13] * e[10] * e[3] + + e[8] * e[5] * e[14] * e[3] - e[4] * e[9] * e[14] * e[3] - e[12] * e[9] * e[2] * e[7] + e[8] * e[13] * e[2] * e[7] + + e[12] * e[1] * e[10] * e[7] - e[0] * e[13] * e[10] * e[7] - e[8] * e[1] * e[14] * e[7] + e[0] * e[9] * e[14] * e[7] + + e[12] * e[5] * e[2] * e[11] - e[4] * e[13] * e[2] * e[11] - e[12] * e[1] * e[6] * e[11] + e[0] * e[13] * e[6] * e[11] + + e[4] * e[1] * e[14] * e[11] - e[0] * e[5] * e[14] * e[11] - e[8] * e[5] * e[2] * e[15] + e[4] * e[9] * e[2] * e[15] + + e[8] * e[1] * e[6] * e[15] - e[0] * e[9] * e[6] * e[15] - e[4] * e[1] * e[10] * e[15] + e[0] * e[5] * e[10] * e[15] + ); + } + + invert(): Matrix4 { + const e = this.buffer; + const det = this.determinant(); + if (det === 0) { + throw new Error("Matrix is not invertible."); + } + const invDet = 1 / det; + // prettier-ignore + return new Matrix4( + invDet * ( + e[5] * e[10] * e[15] - e[5] * e[11] * e[14] - e[9] * e[6] * e[15] + e[9] * e[7] * e[14] + e[13] * e[6] * e[11] - e[13] * e[7] * e[10] + ), + invDet * ( + -e[1] * e[10] * e[15] + e[1] * e[11] * e[14] + e[9] * e[2] * e[15] - e[9] * e[3] * e[14] - e[13] * e[2] * e[11] + e[13] * e[3] * e[10] + ), + invDet * ( + e[1] * e[6] * e[15] - e[1] * e[7] * e[14] - e[5] * e[2] * e[15] + e[5] * e[3] * e[14] + e[13] * e[2] * e[7] - e[13] * e[3] * e[6] + ), + invDet * ( + -e[1] * e[6] * e[11] + e[1] * e[7] * e[10] + e[5] * e[2] * e[11] - e[5] * e[3] * e[10] - e[9] * e[2] * e[7] + e[9] * e[3] * e[6] + ), + invDet * ( + -e[4] * e[10] * e[15] + e[4] * e[11] * e[14] + e[8] * e[6] * e[15] - e[8] * e[7] * e[14] - e[12] * e[6] * e[11] + e[12] * e[7] * e[10] + ), + invDet * ( + e[0] * e[10] * e[15] - e[0] * e[11] * e[14] - e[8] * e[2] * e[15] + e[8] * e[3] * e[14] + e[12] * e[2] * e[11] - e[12] * e[3] * e[10] + ), + invDet * ( + -e[0] * e[6] * e[15] + e[0] * e[7] * e[14] + e[4] * e[2] * e[15] - e[4] * e[3] * e[14] - e[12] * e[2] * e[7] + e[12] * e[3] * e[6] + ), + invDet * ( + e[0] * e[6] * e[11] - e[0] * e[7] * e[10] - e[4] * e[2] * e[11] + e[4] * e[3] * e[10] + e[8] * e[2] * e[7] - e[8] * e[3] * e[6] + ), + invDet * ( + e[4] * e[9] * e[15] - e[4] * e[11] * e[13] - e[8] * e[5] * e[15] + e[8] * e[7] * e[13] + e[12] * e[5] * e[11] - e[12] * e[7] * e[9] + ), + invDet * ( + -e[0] * e[9] * e[15] + e[0] * e[11] * e[13] + e[8] * e[1] * e[15] - e[8] * e[3] * e[13] - e[12] * e[1] * e[11] + e[12] * e[3] * e[9] + ), + invDet * ( + e[0] * e[5] * e[15] - e[0] * e[7] * e[13] - e[4] * e[1] * e[15] + e[4] * e[3] * e[13] + e[12] * e[1] * e[7] - e[12] * e[3] * e[5] + ), + invDet * ( + -e[0] * e[5] * e[11] + e[0] * e[7] * e[9] + e[4] * e[1] * e[11] - e[4] * e[3] * e[9] - e[8] * e[1] * e[7] + e[8] * e[3] * e[5] + ), + invDet * ( + -e[4] * e[9] * e[14] + e[4] * e[10] * e[13] + e[8] * e[5] * e[14] - e[8] * e[6] * e[13] - e[12] * e[5] * e[10] + e[12] * e[6] * e[9] + ), + invDet * ( + e[0] * e[9] * e[14] - e[0] * e[10] * e[13] - e[8] * e[1] * e[14] + e[8] * e[2] * e[13] + e[12] * e[1] * e[10] - e[12] * e[2] * e[9] + ), + invDet * ( + -e[0] * e[5] * e[14] + e[0] * e[6] * e[13] + e[4] * e[1] * e[14] - e[4] * e[2] * e[13] - e[12] * e[1] * e[6] + e[12] * e[2] * e[5] + ), + invDet * ( + e[0] * e[5] * e[10] - e[0] * e[6] * e[9] - e[4] * e[1] * e[10] + e[4] * e[2] * e[9] + e[8] * e[1] * e[6] - e[8] * e[2] * e[5] + ), + ); + } + + static Compose(position: Vector3, rotation: Quaternion, scale: Vector3): Matrix4 { + const x = rotation.x, + y = rotation.y, + z = rotation.z, + w = rotation.w; + const x2 = x + x, + y2 = y + y, + z2 = z + z; + const xx = x * x2, + xy = x * y2, + xz = x * z2; + const yy = y * y2, + yz = y * z2, + zz = z * z2; + const wx = w * x2, + wy = w * y2, + wz = w * z2; + const sx = scale.x, + sy = scale.y, + sz = scale.z; + // prettier-ignore + return new Matrix4( + (1 - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0, + (xy - wz) * sy, (1 - (xx + zz)) * sy, (yz + wx) * sy, 0, + (xz + wy) * sz, (yz - wx) * sz, (1 - (xx + yy)) * sz, 0, + position.x, position.y, position.z, 1 + ); + } + + toString(): string { + return `[${this.buffer.join(", ")}]`; + } +} + +export { Matrix4 }; diff --git a/src/math/Plane.ts b/src/math/Plane.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e07d1470d3085826054d96c2108b2f31cbdf95a --- /dev/null +++ b/src/math/Plane.ts @@ -0,0 +1,29 @@ +import { Vector3 } from "./Vector3"; + +class Plane { + public readonly normal: Vector3; + public readonly point: Vector3; + + constructor(normal: Vector3, point: Vector3) { + this.normal = normal; + this.point = point; + } + + intersect(origin: Vector3, direction: Vector3): Vector3 | null { + const denominator = this.normal.dot(direction); + + if (Math.abs(denominator) < 0.0001) { + return null; + } + + const t = this.normal.dot(this.point.subtract(origin)) / denominator; + + if (t < 0) { + return null; + } + + return origin.add(direction.multiply(t)); + } +} + +export { Plane }; diff --git a/src/math/Quaternion.ts b/src/math/Quaternion.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc04c13fb4aaafbe12363e9803e8fec790d9fe77 --- /dev/null +++ b/src/math/Quaternion.ts @@ -0,0 +1,177 @@ +import { Matrix3 } from "./Matrix3"; +import { Vector3 } from "./Vector3"; + +class Quaternion { + public readonly x: number; + public readonly y: number; + public readonly z: number; + public readonly w: number; + + constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + equals(q: Quaternion): boolean { + if (this.x !== q.x) { + return false; + } + if (this.y !== q.y) { + return false; + } + if (this.z !== q.z) { + return false; + } + if (this.w !== q.w) { + return false; + } + + return true; + } + + normalize(): Quaternion { + const l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + return new Quaternion(this.x / l, this.y / l, this.z / l, this.w / l); + } + + multiply(q: Quaternion): Quaternion { + const w1 = this.w, + x1 = this.x, + y1 = this.y, + z1 = this.z; + const w2 = q.w, + x2 = q.x, + y2 = q.y, + z2 = q.z; + + return new Quaternion( + w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2, + w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2, + w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2, + w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2, + ); + } + + inverse(): Quaternion { + const l = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + return new Quaternion(-this.x / l, -this.y / l, -this.z / l, this.w / l); + } + + apply(v: Vector3): Vector3 { + const vecQuat = new Quaternion(v.x, v.y, v.z, 0); + const conjugate = new Quaternion(-this.x, -this.y, -this.z, this.w); + const rotatedQuat = this.multiply(vecQuat).multiply(conjugate); + return new Vector3(rotatedQuat.x, rotatedQuat.y, rotatedQuat.z); + } + + flat(): number[] { + return [this.x, this.y, this.z, this.w]; + } + + clone(): Quaternion { + return new Quaternion(this.x, this.y, this.z, this.w); + } + + static FromEuler(e: Vector3): Quaternion { + const halfX = e.x / 2; + const halfY = e.y / 2; + const halfZ = e.z / 2; + const cy = Math.cos(halfY); + const sy = Math.sin(halfY); + const cp = Math.cos(halfX); + const sp = Math.sin(halfX); + const cz = Math.cos(halfZ); + const sz = Math.sin(halfZ); + + const q = new Quaternion( + cy * sp * cz + sy * cp * sz, + sy * cp * cz - cy * sp * sz, + cy * cp * sz - sy * sp * cz, + cy * cp * cz + sy * sp * sz, + ); + return q; + } + + toEuler(): Vector3 { + const sinr_cosp = 2 * (this.w * this.x + this.y * this.z); + const cosr_cosp = 1 - 2 * (this.x * this.x + this.y * this.y); + const x = Math.atan2(sinr_cosp, cosr_cosp); + + let y; + const sinp = 2 * (this.w * this.y - this.z * this.x); + if (Math.abs(sinp) >= 1) { + y = (Math.sign(sinp) * Math.PI) / 2; + } else { + y = Math.asin(sinp); + } + + const siny_cosp = 2 * (this.w * this.z + this.x * this.y); + const cosy_cosp = 1 - 2 * (this.y * this.y + this.z * this.z); + const z = Math.atan2(siny_cosp, cosy_cosp); + + return new Vector3(x, y, z); + } + + static FromMatrix3(matrix: Matrix3): Quaternion { + const m = matrix.buffer; + const trace = m[0] + m[4] + m[8]; + let x, y, z, w; + if (trace > 0) { + const s = 0.5 / Math.sqrt(trace + 1.0); + w = 0.25 / s; + x = (m[7] - m[5]) * s; + y = (m[2] - m[6]) * s; + z = (m[3] - m[1]) * s; + } else if (m[0] > m[4] && m[0] > m[8]) { + const s = 2.0 * Math.sqrt(1.0 + m[0] - m[4] - m[8]); + w = (m[7] - m[5]) / s; + x = 0.25 * s; + y = (m[1] + m[3]) / s; + z = (m[2] + m[6]) / s; + } else if (m[4] > m[8]) { + const s = 2.0 * Math.sqrt(1.0 + m[4] - m[0] - m[8]); + w = (m[2] - m[6]) / s; + x = (m[1] + m[3]) / s; + y = 0.25 * s; + z = (m[5] + m[7]) / s; + } else { + const s = 2.0 * Math.sqrt(1.0 + m[8] - m[0] - m[4]); + w = (m[3] - m[1]) / s; + x = (m[2] + m[6]) / s; + y = (m[5] + m[7]) / s; + z = 0.25 * s; + } + return new Quaternion(x, y, z, w); + } + + static FromAxisAngle(axis: Vector3, angle: number): Quaternion { + const halfAngle = angle / 2; + const sin = Math.sin(halfAngle); + const cos = Math.cos(halfAngle); + return new Quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos); + } + + static LookRotation(direction: Vector3): Quaternion { + const forward = new Vector3(0, 0, 1); + const dot = forward.dot(direction); + + if (Math.abs(dot - -1.0) < 0.000001) { + return new Quaternion(0, 1, 0, Math.PI); + } + if (Math.abs(dot - 1.0) < 0.000001) { + return new Quaternion(); + } + + const rotAngle = Math.acos(dot); + const rotAxis = forward.cross(direction).normalize(); + return Quaternion.FromAxisAngle(rotAxis, rotAngle); + } + + toString(): string { + return `[${this.flat().join(", ")}]`; + } +} + +export { Quaternion }; diff --git a/src/math/Vector3.ts b/src/math/Vector3.ts new file mode 100644 index 0000000000000000000000000000000000000000..caa403ae711ce4be7cc257166902d72e21fbdff8 --- /dev/null +++ b/src/math/Vector3.ts @@ -0,0 +1,163 @@ +import { Matrix4 } from "./Matrix4"; + +class Vector3 { + public readonly x: number; + public readonly y: number; + public readonly z: number; + + constructor(x: number = 0, y: number = 0, z: number = 0) { + this.x = x; + this.y = y; + this.z = z; + } + + equals(v: Vector3): boolean { + if (this.x !== v.x) { + return false; + } + if (this.y !== v.y) { + return false; + } + if (this.z !== v.z) { + return false; + } + + return true; + } + + add(v: number): Vector3; + add(v: Vector3): Vector3; + add(v: number | Vector3): Vector3 { + if (typeof v === "number") { + return new Vector3(this.x + v, this.y + v, this.z + v); + } else { + return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z); + } + } + + subtract(v: number): Vector3; + subtract(v: Vector3): Vector3; + subtract(v: number | Vector3): Vector3 { + if (typeof v === "number") { + return new Vector3(this.x - v, this.y - v, this.z - v); + } else { + return new Vector3(this.x - v.x, this.y - v.y, this.z - v.z); + } + } + + multiply(v: number): Vector3; + multiply(v: Vector3): Vector3; + multiply(v: Matrix4): Vector3; + multiply(v: number | Vector3 | Matrix4): Vector3 { + if (typeof v === "number") { + return new Vector3(this.x * v, this.y * v, this.z * v); + } else if (v instanceof Vector3) { + return new Vector3(this.x * v.x, this.y * v.y, this.z * v.z); + } else { + return new Vector3( + this.x * v.buffer[0] + this.y * v.buffer[4] + this.z * v.buffer[8] + v.buffer[12], + this.x * v.buffer[1] + this.y * v.buffer[5] + this.z * v.buffer[9] + v.buffer[13], + this.x * v.buffer[2] + this.y * v.buffer[6] + this.z * v.buffer[10] + v.buffer[14], + ); + } + } + + divide(v: number): Vector3; + divide(v: Vector3): Vector3; + divide(v: number | Vector3): Vector3 { + if (typeof v === "number") { + return new Vector3(this.x / v, this.y / v, this.z / v); + } else { + return new Vector3(this.x / v.x, this.y / v.y, this.z / v.z); + } + } + + cross(v: Vector3): Vector3 { + const x = this.y * v.z - this.z * v.y; + const y = this.z * v.x - this.x * v.z; + const z = this.x * v.y - this.y * v.x; + + return new Vector3(x, y, z); + } + + dot(v: Vector3): number { + return this.x * v.x + this.y * v.y + this.z * v.z; + } + + lerp(v: Vector3, t: number): Vector3 { + return new Vector3(this.x + (v.x - this.x) * t, this.y + (v.y - this.y) * t, this.z + (v.z - this.z) * t); + } + + min(v: Vector3): Vector3 { + return new Vector3(Math.min(this.x, v.x), Math.min(this.y, v.y), Math.min(this.z, v.z)); + } + + max(v: Vector3): Vector3 { + return new Vector3(Math.max(this.x, v.x), Math.max(this.y, v.y), Math.max(this.z, v.z)); + } + + getComponent(axis: number) { + switch (axis) { + case 0: + return this.x; + case 1: + return this.y; + case 2: + return this.z; + default: + throw new Error(`Invalid component index: ${axis}`); + } + } + + minComponent(): number { + if (this.x < this.y && this.x < this.z) { + return 0; + } else if (this.y < this.z) { + return 1; + } else { + return 2; + } + } + + maxComponent(): number { + if (this.x > this.y && this.x > this.z) { + return 0; + } else if (this.y > this.z) { + return 1; + } else { + return 2; + } + } + + magnitude(): number { + return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + } + + distanceTo(v: Vector3): number { + return Math.sqrt((this.x - v.x) ** 2 + (this.y - v.y) ** 2 + (this.z - v.z) ** 2); + } + + normalize(): Vector3 { + const length = this.magnitude(); + + return new Vector3(this.x / length, this.y / length, this.z / length); + } + + flat(): number[] { + return [this.x, this.y, this.z]; + } + + clone(): Vector3 { + return new Vector3(this.x, this.y, this.z); + } + + toString(): string { + return `[${this.flat().join(", ")}]`; + } + + static One(value: number = 1): Vector3 { + return new Vector3(value, value, value); + } +} + +export { Vector3 }; diff --git a/src/math/Vector4.ts b/src/math/Vector4.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d8fefed86e82c9c43d3deb61dc9f2ce7f1e6b91 --- /dev/null +++ b/src/math/Vector4.ts @@ -0,0 +1,111 @@ +import { Matrix4 } from "./Matrix4"; + +class Vector4 { + public readonly x: number; + public readonly y: number; + public readonly z: number; + public readonly w: number; + + constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 0) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + equals(v: Vector4): boolean { + if (this.x !== v.x) { + return false; + } + if (this.y !== v.y) { + return false; + } + if (this.z !== v.z) { + return false; + } + if (this.w !== v.w) { + return false; + } + + return true; + } + + add(v: number): Vector4; + add(v: Vector4): Vector4; + add(v: number | Vector4): Vector4 { + if (typeof v === "number") { + return new Vector4(this.x + v, this.y + v, this.z + v, this.w + v); + } else { + return new Vector4(this.x + v.x, this.y + v.y, this.z + v.z, this.w + v.w); + } + } + + subtract(v: number): Vector4; + subtract(v: Vector4): Vector4; + subtract(v: number | Vector4): Vector4 { + if (typeof v === "number") { + return new Vector4(this.x - v, this.y - v, this.z - v, this.w - v); + } else { + return new Vector4(this.x - v.x, this.y - v.y, this.z - v.z, this.w - v.w); + } + } + + multiply(v: number): Vector4; + multiply(v: Vector4): Vector4; + multiply(v: Matrix4): Vector4; + multiply(v: number | Vector4 | Matrix4): Vector4 { + if (typeof v === "number") { + return new Vector4(this.x * v, this.y * v, this.z * v, this.w * v); + } else if (v instanceof Vector4) { + return new Vector4(this.x * v.x, this.y * v.y, this.z * v.z, this.w * v.w); + } else { + return new Vector4( + this.x * v.buffer[0] + this.y * v.buffer[4] + this.z * v.buffer[8] + this.w * v.buffer[12], + this.x * v.buffer[1] + this.y * v.buffer[5] + this.z * v.buffer[9] + this.w * v.buffer[13], + this.x * v.buffer[2] + this.y * v.buffer[6] + this.z * v.buffer[10] + this.w * v.buffer[14], + this.x * v.buffer[3] + this.y * v.buffer[7] + this.z * v.buffer[11] + this.w * v.buffer[15], + ); + } + } + + dot(v: Vector4): number { + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + } + + lerp(v: Vector4, t: number): Vector4 { + return new Vector4( + this.x + (v.x - this.x) * t, + this.y + (v.y - this.y) * t, + this.z + (v.z - this.z) * t, + this.w + (v.w - this.w) * t, + ); + } + + magnitude(): number { + return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + } + + distanceTo(v: Vector4): number { + return Math.sqrt((this.x - v.x) ** 2 + (this.y - v.y) ** 2 + (this.z - v.z) ** 2 + (this.w - v.w) ** 2); + } + + normalize(): Vector4 { + const length = this.magnitude(); + + return new Vector4(this.x / length, this.y / length, this.z / length, this.w / length); + } + + flat(): number[] { + return [this.x, this.y, this.z, this.w]; + } + + clone(): Vector4 { + return new Vector4(this.x, this.y, this.z, this.w); + } + + toString(): string { + return `[${this.flat().join(", ")}]`; + } +} + +export { Vector4 }; diff --git a/src/renderers/WebGLRenderer.ts b/src/renderers/WebGLRenderer.ts new file mode 100644 index 0000000000000000000000000000000000000000..c87af3b7c2df05e81f95183d6608be1fda3b8bb3 --- /dev/null +++ b/src/renderers/WebGLRenderer.ts @@ -0,0 +1,110 @@ +import type { Scene } from "../core/Scene"; +import { FadeInPass } from "./webgl/passes/FadeInPass"; +import { Camera } from "../cameras/Camera"; +import { Color32 } from "../math/Color32"; +import { ShaderProgram } from "./webgl/programs/ShaderProgram"; +import { RenderProgram } from "./webgl/programs/RenderProgram"; +import { ShaderPass } from "./webgl/passes/ShaderPass"; + +export class WebGLRenderer { + private _canvas: HTMLCanvasElement; + private _gl: WebGL2RenderingContext; + private _backgroundColor: Color32 = new Color32(); + private _renderProgram: RenderProgram; + + addProgram: (program: ShaderProgram) => void; + removeProgram: (program: ShaderProgram) => void; + resize: () => void; + setSize: (width: number, height: number) => void; + render: (scene: Scene, camera: Camera) => void; + dispose: () => void; + + constructor(optionalCanvas: HTMLCanvasElement | null = null, optionalRenderPasses: ShaderPass[] | null = null) { + const canvas: HTMLCanvasElement = optionalCanvas || document.createElement("canvas"); + if (!optionalCanvas) { + canvas.style.display = "block"; + canvas.style.boxSizing = "border-box"; + canvas.style.width = "100%"; + canvas.style.height = "100%"; + canvas.style.margin = "0"; + canvas.style.padding = "0"; + document.body.appendChild(canvas); + } + canvas.style.background = this._backgroundColor.toHexString(); + this._canvas = canvas; + + this._gl = canvas.getContext("webgl2", { antialias: false }) as WebGL2RenderingContext; + + const renderPasses = optionalRenderPasses || []; + if (!optionalRenderPasses) { + renderPasses.push(new FadeInPass()); + } + + this._renderProgram = new RenderProgram(this, renderPasses); + const programs = [this._renderProgram] as ShaderProgram[]; + + this.resize = () => { + const width = canvas.clientWidth; + const height = canvas.clientHeight; + if (canvas.width !== width || canvas.height !== height) { + this.setSize(width, height); + } + }; + + this.setSize = (width: number, height: number) => { + canvas.width = width; + canvas.height = height; + this._gl.viewport(0, 0, canvas.width, canvas.height); + for (const program of programs) { + program.resize(); + } + }; + + this.render = (scene: Scene, camera: Camera) => { + for (const program of programs) { + program.render(scene, camera); + } + }; + + this.dispose = () => { + for (const program of programs) { + program.dispose(); + } + }; + + this.addProgram = (program: ShaderProgram) => { + programs.push(program); + }; + + this.removeProgram = (program: ShaderProgram) => { + const index = programs.indexOf(program); + if (index < 0) { + throw new Error("Program not found"); + } + programs.splice(index, 1); + }; + + this.resize(); + } + + get canvas() { + return this._canvas; + } + + get gl() { + return this._gl; + } + + get renderProgram() { + return this._renderProgram; + } + + get backgroundColor() { + return this._backgroundColor; + } + + set backgroundColor(value: Color32) { + this._backgroundColor = value; + this._canvas.style.background = value.toHexString(); + } +} diff --git a/src/renderers/webgl/passes/FadeInPass.ts b/src/renderers/webgl/passes/FadeInPass.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bd45752f3c5cb98e83b7f16076b3335849e8e41 --- /dev/null +++ b/src/renderers/webgl/passes/FadeInPass.ts @@ -0,0 +1,50 @@ +import { RenderProgram } from "../programs/RenderProgram"; +import { ShaderProgram } from "../programs/ShaderProgram"; +import { ShaderPass } from "./ShaderPass"; + +class FadeInPass implements ShaderPass { + initialize: (program: ShaderProgram) => void; + render: () => void; + + constructor(speed: number = 1.0) { + let value = 0.0; + let active = false; + + let renderProgram: RenderProgram; + let gl: WebGL2RenderingContext; + let u_useDepthFade: WebGLUniformLocation; + let u_depthFade: WebGLUniformLocation; + + this.initialize = (program: ShaderProgram) => { + if (!(program instanceof RenderProgram)) { + throw new Error("FadeInPass requires a RenderProgram"); + } + + value = program.started ? 1.0 : 0.0; + active = true; + renderProgram = program; + gl = program.renderer.gl; + + u_useDepthFade = gl.getUniformLocation(renderProgram.program, "useDepthFade") as WebGLUniformLocation; + gl.uniform1i(u_useDepthFade, 1); + + u_depthFade = gl.getUniformLocation(renderProgram.program, "depthFade") as WebGLUniformLocation; + gl.uniform1f(u_depthFade, value); + }; + + this.render = () => { + if (!active || renderProgram.renderData?.updating) return; + gl.useProgram(renderProgram.program); + value = Math.min(value + speed * 0.01, 1.0); + if (value >= 1.0) { + active = false; + gl.uniform1i(u_useDepthFade, 0); + } + gl.uniform1f(u_depthFade, value); + }; + } + + dispose() {} +} + +export { FadeInPass }; diff --git a/src/renderers/webgl/passes/ShaderPass.ts b/src/renderers/webgl/passes/ShaderPass.ts new file mode 100644 index 0000000000000000000000000000000000000000..0906d298c0af0f73aaf15d7773e17957f32d78fd --- /dev/null +++ b/src/renderers/webgl/passes/ShaderPass.ts @@ -0,0 +1,10 @@ +import { ShaderProgram } from "../programs/ShaderProgram"; + +class ShaderPass { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + initialize(program: ShaderProgram) {} + render() {} + dispose() {} +} + +export { ShaderPass }; diff --git a/src/renderers/webgl/programs/RenderProgram.ts b/src/renderers/webgl/programs/RenderProgram.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e53acab61eaa7a0363f057f2ebd6ec24f8e9bfc --- /dev/null +++ b/src/renderers/webgl/programs/RenderProgram.ts @@ -0,0 +1,574 @@ +import SortWorker from "web-worker:../utils/SortWorker.ts"; + +import { ShaderProgram } from "./ShaderProgram"; +import { ShaderPass } from "../passes/ShaderPass"; +import { RenderData } from "../utils/RenderData"; +import { Color32 } from "../../../math/Color32"; +import { ObjectAddedEvent, ObjectChangedEvent, ObjectRemovedEvent } from "../../../events/Events"; +import { Splat } from "../../../splats/Splat"; +import { WebGLRenderer } from "../../WebGLRenderer"; +import { Scene } from "../../../core/Scene" + +const vertexShaderSource = /* glsl */ `#version 300 es +precision highp float; +precision highp int; + +uniform highp usampler2D u_texture; +uniform highp sampler2D u_transforms; +uniform highp usampler2D u_transformIndices; +uniform highp sampler2D u_colorTransforms; +uniform highp usampler2D u_colorTransformIndices; +uniform mat4 projection, view; +uniform vec2 focal; +uniform vec2 viewport; + +uniform bool useDepthFade; +uniform float depthFade; + +in vec2 position; +in int index; + +out vec4 vColor; +out vec2 vPosition; +out float vSize; +out float vSelected; + +void main () { + uvec4 cen = texelFetch(u_texture, ivec2((uint(index) & 0x3ffu) << 1, uint(index) >> 10), 0); + float selected = float((cen.w >> 24) & 0xffu); + + uint transformIndex = texelFetch(u_transformIndices, ivec2(uint(index) & 0x3ffu, uint(index) >> 10), 0).x; + mat4 transform = mat4( + texelFetch(u_transforms, ivec2(0, transformIndex), 0), + texelFetch(u_transforms, ivec2(1, transformIndex), 0), + texelFetch(u_transforms, ivec2(2, transformIndex), 0), + texelFetch(u_transforms, ivec2(3, transformIndex), 0) + ); + + if (selected < 0.5) { + selected = texelFetch(u_transforms, ivec2(4, transformIndex), 0).x; + } + + mat4 viewTransform = view * transform; + + vec4 cam = viewTransform * vec4(uintBitsToFloat(cen.xyz), 1); + vec4 pos2d = projection * cam; + + float clip = 1.2 * pos2d.w; + if (pos2d.z < -pos2d.w || pos2d.z > pos2d.w || pos2d.x < -clip || pos2d.x > clip || pos2d.y < -clip || pos2d.y > clip) { + gl_Position = vec4(0.0, 0.0, 2.0, 1.0); + return; + } + + uvec4 cov = texelFetch(u_texture, ivec2(((uint(index) & 0x3ffu) << 1) | 1u, uint(index) >> 10), 0); + vec2 u1 = unpackHalf2x16(cov.x), u2 = unpackHalf2x16(cov.y), u3 = unpackHalf2x16(cov.z); + mat3 Vrk = mat3(u1.x, u1.y, u2.x, u1.y, u2.y, u3.x, u2.x, u3.x, u3.y); + + mat3 J = mat3( + focal.x / cam.z, 0., -(focal.x * cam.x) / (cam.z * cam.z), + 0., -focal.y / cam.z, (focal.y * cam.y) / (cam.z * cam.z), + 0., 0., 0. + ); + + mat3 T = transpose(mat3(viewTransform)) * J; + mat3 cov2d = transpose(T) * Vrk * T; + + //ref: https://github.com/graphdeco-inria/diff-gaussian-rasterization/blob/main/cuda_rasterizer/forward.cu#L110-L111 + cov2d[0][0] += 0.3; + cov2d[1][1] += 0.3; + + float mid = (cov2d[0][0] + cov2d[1][1]) / 2.0; + float radius = length(vec2((cov2d[0][0] - cov2d[1][1]) / 2.0, cov2d[0][1])); + float lambda1 = mid + radius, lambda2 = mid - radius; + + if (lambda2 < 0.0) return; + vec2 diagonalVector = normalize(vec2(cov2d[0][1], lambda1 - cov2d[0][0])); + vec2 majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector; + vec2 minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x); + + uint colorTransformIndex = texelFetch(u_colorTransformIndices, ivec2(uint(index) & 0x3ffu, uint(index) >> 10), 0).x; + mat4 colorTransform = mat4( + texelFetch(u_colorTransforms, ivec2(0, colorTransformIndex), 0), + texelFetch(u_colorTransforms, ivec2(1, colorTransformIndex), 0), + texelFetch(u_colorTransforms, ivec2(2, colorTransformIndex), 0), + texelFetch(u_colorTransforms, ivec2(3, colorTransformIndex), 0) + ); + + vec4 color = vec4((cov.w) & 0xffu, (cov.w >> 8) & 0xffu, (cov.w >> 16) & 0xffu, (cov.w >> 24) & 0xffu) / 255.0; + vColor = colorTransform * color; + + vPosition = position; + vSize = length(majorAxis); + vSelected = selected; + + float scalingFactor = 1.0; + + if (useDepthFade) { + float depthNorm = (pos2d.z / pos2d.w + 1.0) / 2.0; + float near = 0.1; float far = 100.0; + float normalizedDepth = (2.0 * near) / (far + near - depthNorm * (far - near)); + float start = max(normalizedDepth - 0.1, 0.0); + float end = min(normalizedDepth + 0.1, 1.0); + scalingFactor = clamp((depthFade - start) / (end - start), 0.0, 1.0); + } + + vec2 vCenter = vec2(pos2d) / pos2d.w; + gl_Position = vec4( + vCenter + + position.x * majorAxis * scalingFactor / viewport + + position.y * minorAxis * scalingFactor / viewport, 0.0, 1.0); +} +`; + +const fragmentShaderSource = /* glsl */ `#version 300 es +precision highp float; + +uniform float outlineThickness; +uniform vec4 outlineColor; + +in vec4 vColor; +in vec2 vPosition; +in float vSize; +in float vSelected; + +out vec4 fragColor; + +void main () { + float A = -dot(vPosition, vPosition); + + if (A < -4.0) discard; + + if (vSelected < 0.5) { + float B = exp(A) * vColor.a; + fragColor = vec4(B * vColor.rgb, B); + return; + } + + float outlineThreshold = -4.0 + (outlineThickness / vSize); + + if (A < outlineThreshold) { + fragColor = outlineColor; + } + else { + float B = exp(A) * vColor.a; + fragColor = vec4(B * vColor.rgb, B); + } +} +`; + +class RenderProgram extends ShaderProgram { + private _outlineThickness: number = 10.0; + private _outlineColor: Color32 = new Color32(255, 165, 0, 255); + private _renderData: RenderData | null = null; + private _depthIndex: Uint32Array = new Uint32Array(); + private _splatTexture: WebGLTexture | null = null; + private _worker: Worker | null = null; + + protected _initialize: () => void; + protected _resize: () => void; + protected _render: () => void; + protected _dispose: () => void; + + private _setOutlineThickness: (value: number) => void; + private _setOutlineColor: (value: Color32) => void; + + constructor(renderer: WebGLRenderer, passes: ShaderPass[]) { + super(renderer, passes); + + const canvas = renderer.canvas; + const gl = renderer.gl; + + let u_projection: WebGLUniformLocation; + let u_viewport: WebGLUniformLocation; + let u_focal: WebGLUniformLocation; + let u_view: WebGLUniformLocation; + let u_texture: WebGLUniformLocation; + let u_transforms: WebGLUniformLocation; + let u_transformIndices: WebGLUniformLocation; + let u_colorTransforms: WebGLUniformLocation; + let u_colorTransformIndices: WebGLUniformLocation; + + let u_outlineThickness: WebGLUniformLocation; + let u_outlineColor: WebGLUniformLocation; + + let positionAttribute: number; + let indexAttribute: number; + + let transformsTexture: WebGLTexture; + let transformIndicesTexture: WebGLTexture; + + let colorTransformsTexture: WebGLTexture; + let colorTransformIndicesTexture: WebGLTexture; + + let vertexBuffer: WebGLBuffer; + let indexBuffer: WebGLBuffer; + + this._resize = () => { + if (!this._camera) return; + + this._camera.data.setSize(canvas.width, canvas.height); + this._camera.update(); + + u_projection = gl.getUniformLocation(this.program, "projection") as WebGLUniformLocation; + gl.uniformMatrix4fv(u_projection, false, this._camera.data.projectionMatrix.buffer); + + u_viewport = gl.getUniformLocation(this.program, "viewport") as WebGLUniformLocation; + gl.uniform2fv(u_viewport, new Float32Array([canvas.width, canvas.height])); + }; + + const createWorker = () => { + this._worker = new SortWorker(); + this._worker.onmessage = (e) => { + if (e.data.depthIndex) { + const { depthIndex } = e.data; + this._depthIndex = depthIndex; + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, depthIndex, gl.STATIC_DRAW); + } + }; + }; + + this._initialize = () => { + if (!this._scene || !this._camera) { + console.error("Cannot render without scene and camera"); + return; + } + + this._resize(); + + this._scene.addEventListener("objectAdded", handleObjectAdded); + this._scene.addEventListener("objectRemoved", handleObjectRemoved); + for (const object of this._scene.objects) { + if (object instanceof Splat) { + object.addEventListener("objectChanged", handleObjectChanged); + } + } + + this._renderData = new RenderData(this._scene); + + u_focal = gl.getUniformLocation(this.program, "focal") as WebGLUniformLocation; + gl.uniform2fv(u_focal, new Float32Array([this._camera.data.fx, this._camera.data.fy])); + + u_view = gl.getUniformLocation(this.program, "view") as WebGLUniformLocation; + gl.uniformMatrix4fv(u_view, false, this._camera.data.viewMatrix.buffer); + + u_outlineThickness = gl.getUniformLocation(this.program, "outlineThickness") as WebGLUniformLocation; + gl.uniform1f(u_outlineThickness, this.outlineThickness); + + u_outlineColor = gl.getUniformLocation(this.program, "outlineColor") as WebGLUniformLocation; + gl.uniform4fv(u_outlineColor, new Float32Array(this.outlineColor.flatNorm())); + + this._splatTexture = gl.createTexture() as WebGLTexture; + u_texture = gl.getUniformLocation(this.program, "u_texture") as WebGLUniformLocation; + gl.uniform1i(u_texture, 0); + + transformsTexture = gl.createTexture() as WebGLTexture; + u_transforms = gl.getUniformLocation(this.program, "u_transforms") as WebGLUniformLocation; + gl.uniform1i(u_transforms, 1); + + transformIndicesTexture = gl.createTexture() as WebGLTexture; + u_transformIndices = gl.getUniformLocation(this.program, "u_transformIndices") as WebGLUniformLocation; + gl.uniform1i(u_transformIndices, 2); + + colorTransformsTexture = gl.createTexture() as WebGLTexture; + u_colorTransforms = gl.getUniformLocation(this.program, "u_colorTransforms") as WebGLUniformLocation; + gl.uniform1i(u_colorTransforms, 3); + + colorTransformIndicesTexture = gl.createTexture() as WebGLTexture; + u_colorTransformIndices = gl.getUniformLocation( + this.program, + "u_colorTransformIndices", + ) as WebGLUniformLocation; + gl.uniform1i(u_colorTransformIndices, 4); + + vertexBuffer = gl.createBuffer() as WebGLBuffer; + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-2, -2, 2, -2, 2, 2, -2, 2]), gl.STATIC_DRAW); + + positionAttribute = gl.getAttribLocation(this.program, "position"); + gl.enableVertexAttribArray(positionAttribute); + gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0); + + indexBuffer = gl.createBuffer() as WebGLBuffer; + indexAttribute = gl.getAttribLocation(this.program, "index"); + gl.enableVertexAttribArray(indexAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + + createWorker(); + }; + + const handleObjectAdded = (event: Event) => { + const e = event as ObjectAddedEvent; + + if (e.object instanceof Splat) { + e.object.addEventListener("objectChanged", handleObjectChanged); + } + + resetSplatData(); + }; + + const handleObjectRemoved = (event: Event) => { + const e = event as ObjectRemovedEvent; + + if (e.object instanceof Splat) { + e.object.removeEventListener("objectChanged", handleObjectChanged); + } + + resetSplatData(); + }; + + const handleObjectChanged = (event: Event) => { + const e = event as ObjectChangedEvent; + + if (e.object instanceof Splat && this._renderData) { + this._renderData.markDirty(e.object); + } + }; + + const resetSplatData = () => { + this._renderData?.dispose(); + this._renderData = new RenderData(this._scene as Scene); + + this._worker?.terminate(); + createWorker(); + }; + + this._render = () => { + if (!this._scene || !this._camera || !this.renderData) { + console.error("Cannot render without scene and camera"); + return; + } + + if (this.renderData.needsRebuild) { + this.renderData.rebuild(); + } + + if ( + this.renderData.dataChanged || + this.renderData.transformsChanged || + this.renderData.colorTransformsChanged + ) { + if (this.renderData.dataChanged) { + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.splatTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA32UI, + this.renderData.width, + this.renderData.height, + 0, + gl.RGBA_INTEGER, + gl.UNSIGNED_INT, + this.renderData.data, + ); + } + + if (this.renderData.transformsChanged) { + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, transformsTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA32F, + this.renderData.transformsWidth, + this.renderData.transformsHeight, + 0, + gl.RGBA, + gl.FLOAT, + this.renderData.transforms, + ); + + gl.activeTexture(gl.TEXTURE2); + gl.bindTexture(gl.TEXTURE_2D, transformIndicesTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.R32UI, + this.renderData.transformIndicesWidth, + this.renderData.transformIndicesHeight, + 0, + gl.RED_INTEGER, + gl.UNSIGNED_INT, + this.renderData.transformIndices, + ); + } + + if (this.renderData.colorTransformsChanged) { + gl.activeTexture(gl.TEXTURE3); + gl.bindTexture(gl.TEXTURE_2D, colorTransformsTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA32F, + this.renderData.colorTransformsWidth, + this.renderData.colorTransformsHeight, + 0, + gl.RGBA, + gl.FLOAT, + this.renderData.colorTransforms, + ); + + gl.activeTexture(gl.TEXTURE4); + gl.bindTexture(gl.TEXTURE_2D, colorTransformIndicesTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.R32UI, + this.renderData.colorTransformIndicesWidth, + this.renderData.colorTransformIndicesHeight, + 0, + gl.RED_INTEGER, + gl.UNSIGNED_INT, + this.renderData.colorTransformIndices, + ); + } + + const detachedPositions = new Float32Array(this.renderData.positions.slice().buffer); + const detachedTransforms = new Float32Array(this.renderData.transforms.slice().buffer); + const detachedTransformIndices = new Uint32Array(this.renderData.transformIndices.slice().buffer); + this._worker?.postMessage( + { + sortData: { + positions: detachedPositions, + transforms: detachedTransforms, + transformIndices: detachedTransformIndices, + vertexCount: this.renderData.vertexCount, + }, + }, + [detachedPositions.buffer, detachedTransforms.buffer, detachedTransformIndices.buffer], + ); + + this.renderData.dataChanged = false; + this.renderData.transformsChanged = false; + this.renderData.colorTransformsChanged = false; + } + + this._camera.update(); + this._worker?.postMessage({ viewProj: this._camera.data.viewProj.buffer }); + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.disable(gl.DEPTH_TEST); + gl.enable(gl.BLEND); + gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE); + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + + gl.uniformMatrix4fv(u_projection, false, this._camera.data.projectionMatrix.buffer); + gl.uniformMatrix4fv(u_view, false, this._camera.data.viewMatrix.buffer); + + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.depthIndex, gl.STATIC_DRAW); + gl.vertexAttribIPointer(indexAttribute, 1, gl.INT, 0, 0); + gl.vertexAttribDivisor(indexAttribute, 1); + + gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.depthIndex.length); + }; + + this._dispose = () => { + if (!this._scene || !this._camera || !this.renderData) { + console.error("Cannot dispose without scene and camera"); + return; + } + + this._scene.removeEventListener("objectAdded", handleObjectAdded); + this._scene.removeEventListener("objectRemoved", handleObjectRemoved); + for (const object of this._scene.objects) { + if (object instanceof Splat) { + object.removeEventListener("objectChanged", handleObjectChanged); + } + } + + this._worker?.terminate(); + this.renderData.dispose(); + + gl.deleteTexture(this.splatTexture); + gl.deleteTexture(transformsTexture); + gl.deleteTexture(transformIndicesTexture); + + gl.deleteBuffer(indexBuffer); + gl.deleteBuffer(vertexBuffer); + }; + + this._setOutlineThickness = (value: number) => { + this._outlineThickness = value; + if (this._initialized) { + gl.uniform1f(u_outlineThickness, value); + } + }; + + this._setOutlineColor = (value: Color32) => { + this._outlineColor = value; + if (this._initialized) { + gl.uniform4fv(u_outlineColor, new Float32Array(value.flatNorm())); + } + }; + } + + get renderData() { + return this._renderData; + } + + get depthIndex() { + return this._depthIndex; + } + + get splatTexture() { + return this._splatTexture; + } + + get outlineThickness() { + return this._outlineThickness; + } + + set outlineThickness(value: number) { + this._setOutlineThickness(value); + } + + get outlineColor() { + return this._outlineColor; + } + + set outlineColor(value: Color32) { + this._setOutlineColor(value); + } + + get worker() { + return this._worker; + } + + protected _getVertexSource() { + return vertexShaderSource; + } + + protected _getFragmentSource() { + return fragmentShaderSource; + } +} + +export { RenderProgram }; diff --git a/src/renderers/webgl/programs/ShaderProgram.ts b/src/renderers/webgl/programs/ShaderProgram.ts new file mode 100644 index 0000000000000000000000000000000000000000..da6d8d9d2b7ef386f40ecd6f724c9c5f6d1ad123 --- /dev/null +++ b/src/renderers/webgl/programs/ShaderProgram.ts @@ -0,0 +1,136 @@ +import { Camera } from "../../../cameras/Camera"; +import { Scene } from "../../../core/Scene"; +import { WebGLRenderer } from "../../WebGLRenderer"; +import { ShaderPass } from "../passes/ShaderPass"; + +abstract class ShaderProgram { + private _renderer: WebGLRenderer; + private _program: WebGLProgram; + private _passes: ShaderPass[]; + + protected _scene: Scene | null = null; + protected _camera: Camera | null = null; + protected _started: boolean = false; + protected _initialized: boolean = false; + + protected abstract _initialize: () => void; + protected abstract _resize: () => void; + protected abstract _render: () => void; + protected abstract _dispose: () => void; + + initialize: () => void; + resize: () => void; + render: (scene: Scene, camera: Camera) => void; + dispose: () => void; + + constructor(renderer: WebGLRenderer, passes: ShaderPass[]) { + this._renderer = renderer; + const gl = renderer.gl; + + this._program = gl.createProgram() as WebGLProgram; + this._passes = passes || []; + + const vertexShader = gl.createShader(gl.VERTEX_SHADER) as WebGLShader; + gl.shaderSource(vertexShader, this._getVertexSource()); + gl.compileShader(vertexShader); + if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { + console.error(gl.getShaderInfoLog(vertexShader)); + } + + const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) as WebGLShader; + gl.shaderSource(fragmentShader, this._getFragmentSource()); + gl.compileShader(fragmentShader); + if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { + console.error(gl.getShaderInfoLog(fragmentShader)); + } + + gl.attachShader(this.program, vertexShader); + gl.attachShader(this.program, fragmentShader); + gl.linkProgram(this.program); + if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { + console.error(gl.getProgramInfoLog(this.program)); + } + + this.resize = () => { + gl.useProgram(this._program); + + this._resize(); + }; + + this.initialize = () => { + console.assert(!this._initialized, "ShaderProgram already initialized"); + + gl.useProgram(this._program); + + this._initialize(); + for (const pass of this.passes) { + pass.initialize(this); + } + + this._initialized = true; + this._started = true; + }; + + this.render = (scene: Scene, camera: Camera) => { + gl.useProgram(this._program); + + if (this._scene !== scene || this._camera !== camera) { + this.dispose(); + this._scene = scene; + this._camera = camera; + this.initialize(); + } + + for (const pass of this.passes) { + pass.render(); + } + + this._render(); + }; + + this.dispose = () => { + if (!this._initialized) return; + + gl.useProgram(this._program); + + for (const pass of this.passes) { + pass.dispose(); + } + + this._dispose(); + + this._scene = null; + this._camera = null; + this._initialized = false; + }; + } + + get renderer() { + return this._renderer; + } + + get scene() { + return this._scene; + } + + get camera() { + return this._camera; + } + + get program() { + return this._program; + } + + get passes() { + return this._passes; + } + + get started() { + return this._started; + } + + protected abstract _getVertexSource(): string; + protected abstract _getFragmentSource(): string; +} + +export { ShaderProgram }; diff --git a/src/renderers/webgl/programs/VideoRenderProgram.ts b/src/renderers/webgl/programs/VideoRenderProgram.ts new file mode 100644 index 0000000000000000000000000000000000000000..78c5bb0ed3b0c2e6dcedf64e1acf4a2d771c7688 --- /dev/null +++ b/src/renderers/webgl/programs/VideoRenderProgram.ts @@ -0,0 +1,378 @@ +import { Splatv } from "../../../splats/Splatv"; +import { SplatvData } from "../../../splats/SplatvData"; +import { WebGLRenderer } from "../../WebGLRenderer"; +import { ShaderPass } from "../passes/ShaderPass"; +import { ShaderProgram } from "./ShaderProgram"; +import { ObjectAddedEvent, ObjectChangedEvent, ObjectRemovedEvent } from "../../../events/Events"; +import { Matrix4 } from "../../../math/Matrix4"; + +const vertexShaderSource = /* glsl */ `#version 300 es +precision highp float; +precision highp int; + +uniform highp usampler2D u_texture; +uniform mat4 projection, view; +uniform vec2 focal; +uniform vec2 viewport; +uniform float time; + +in vec2 position; +in int index; + +out vec4 vColor; +out vec2 vPosition; + +void main () { + gl_Position = vec4(0.0, 0.0, 2.0, 1.0); + + uvec4 motion1 = texelFetch(u_texture, ivec2(((uint(index) & 0x3ffu) << 2) | 3u, uint(index) >> 10), 0); + vec2 trbf = unpackHalf2x16(motion1.w); + float dt = time - trbf.x; + + float topacity = exp(-1.0 * pow(dt / trbf.y, 2.0)); + if(topacity < 0.02) return; + + uvec4 motion0 = texelFetch(u_texture, ivec2(((uint(index) & 0x3ffu) << 2) | 2u, uint(index) >> 10), 0); + uvec4 static0 = texelFetch(u_texture, ivec2(((uint(index) & 0x3ffu) << 2), uint(index) >> 10), 0); + + vec2 m0 = unpackHalf2x16(motion0.x), m1 = unpackHalf2x16(motion0.y), m2 = unpackHalf2x16(motion0.z), + m3 = unpackHalf2x16(motion0.w), m4 = unpackHalf2x16(motion1.x); + + vec4 trot = vec4(unpackHalf2x16(motion1.y).xy, unpackHalf2x16(motion1.z).xy) * dt; + vec3 tpos = (vec3(m0.xy, m1.x) * dt + vec3(m1.y, m2.xy) * dt*dt + vec3(m3.xy, m4.x) * dt*dt*dt); + + vec4 cam = view * vec4(uintBitsToFloat(static0.xyz) + tpos, 1); + vec4 pos = projection * cam; + + float clip = 1.2 * pos.w; + if (pos.z < -clip || pos.x < -clip || pos.x > clip || pos.y < -clip || pos.y > clip) return; + uvec4 static1 = texelFetch(u_texture, ivec2(((uint(index) & 0x3ffu) << 2) | 1u, uint(index) >> 10), 0); + + vec4 rot = vec4(unpackHalf2x16(static0.w).xy, unpackHalf2x16(static1.x).xy) + trot; + vec3 scale = vec3(unpackHalf2x16(static1.y).xy, unpackHalf2x16(static1.z).x); + rot /= sqrt(dot(rot, rot)); + + mat3 S = mat3(scale.x, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, scale.z); + mat3 R = mat3( + 1.0 - 2.0 * (rot.z * rot.z + rot.w * rot.w), 2.0 * (rot.y * rot.z - rot.x * rot.w), 2.0 * (rot.y * rot.w + rot.x * rot.z), + 2.0 * (rot.y * rot.z + rot.x * rot.w), 1.0 - 2.0 * (rot.y * rot.y + rot.w * rot.w), 2.0 * (rot.z * rot.w - rot.x * rot.y), + 2.0 * (rot.y * rot.w - rot.x * rot.z), 2.0 * (rot.z * rot.w + rot.x * rot.y), 1.0 - 2.0 * (rot.y * rot.y + rot.z * rot.z)); + mat3 M = S * R; + mat3 Vrk = 4.0 * transpose(M) * M; + mat3 J = mat3( + focal.x / cam.z, 0., -(focal.x * cam.x) / (cam.z * cam.z), + 0., -focal.y / cam.z, (focal.y * cam.y) / (cam.z * cam.z), + 0., 0., 0. + ); + + mat3 T = transpose(mat3(view)) * J; + mat3 cov2d = transpose(T) * Vrk * T; + + float mid = (cov2d[0][0] + cov2d[1][1]) / 2.0; + float radius = length(vec2((cov2d[0][0] - cov2d[1][1]) / 2.0, cov2d[0][1])); + float lambda1 = mid + radius, lambda2 = mid - radius; + + if(lambda2 < 0.0) return; + vec2 diagonalVector = normalize(vec2(cov2d[0][1], lambda1 - cov2d[0][0])); + vec2 majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector; + vec2 minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x); + + uint rgba = static1.w; + vColor = + clamp(pos.z/pos.w+1.0, 0.0, 1.0) * + vec4(1.0, 1.0, 1.0, topacity) * + vec4( + (rgba) & 0xffu, + (rgba >> 8) & 0xffu, + (rgba >> 16) & 0xffu, + (rgba >> 24) & 0xffu) / 255.0; + + vec2 vCenter = vec2(pos) / pos.w; + gl_Position = vec4( + vCenter + + position.x * majorAxis / viewport + + position.y * minorAxis / viewport, 0.0, 1.0); + + vPosition = position; +} +`; + +const fragmentShaderSource = /* glsl */ `#version 300 es +precision highp float; + +in vec4 vColor; +in vec2 vPosition; + +out vec4 fragColor; + +void main () { + float A = -dot(vPosition, vPosition); + if (A < -4.0) discard; + float B = exp(A) * vColor.a; + fragColor = vec4(B * vColor.rgb, B); +} +`; + +class VideoRenderProgram extends ShaderProgram { + private _renderData: SplatvData | null = null; + private _depthIndex: Uint32Array = new Uint32Array(); + private _splatTexture: WebGLTexture | null = null; + + protected _initialize: () => void; + protected _resize: () => void; + protected _render: () => void; + protected _dispose: () => void; + + constructor(renderer: WebGLRenderer, passes: ShaderPass[] = []) { + super(renderer, passes); + + const canvas = renderer.canvas; + const gl = renderer.gl; + + let worker: Worker; + + let u_projection: WebGLUniformLocation; + let u_viewport: WebGLUniformLocation; + let u_focal: WebGLUniformLocation; + let u_view: WebGLUniformLocation; + let u_texture: WebGLUniformLocation; + let u_time: WebGLUniformLocation; + + let positionAttribute: number; + let indexAttribute: number; + + let vertexBuffer: WebGLBuffer; + let indexBuffer: WebGLBuffer; + + this._resize = () => { + if (!this._camera) return; + + this._camera.data.setSize(canvas.width, canvas.height); + this._camera.update(); + + u_projection = gl.getUniformLocation(this.program, "projection") as WebGLUniformLocation; + gl.uniformMatrix4fv(u_projection, false, this._camera.data.projectionMatrix.buffer); + + u_viewport = gl.getUniformLocation(this.program, "viewport") as WebGLUniformLocation; + gl.uniform2fv(u_viewport, new Float32Array([canvas.width, canvas.height])); + }; + + const setupWorker = () => { + if (renderer.renderProgram.worker === null) { + console.error("Render program is not initialized. Cannot render without worker"); + return; + } + worker = renderer.renderProgram.worker; + worker.onmessage = (e) => { + if (e.data.depthIndex) { + const { depthIndex } = e.data; + this._depthIndex = depthIndex; + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, depthIndex, gl.STATIC_DRAW); + } + }; + }; + + this._initialize = () => { + if (!this._scene || !this._camera) { + console.error("Cannot render without scene and camera"); + return; + } + + this._resize(); + + this._scene.addEventListener("objectAdded", handleObjectAdded); + this._scene.addEventListener("objectRemoved", handleObjectRemoved); + for (const object of this._scene.objects) { + if (object instanceof Splatv) { + if (this._renderData === null) { + this._renderData = object.data; + object.addEventListener("objectChanged", handleObjectChanged); + } else { + console.warn("Multiple Splatv objects are not currently supported"); + } + } + } + + if (this._renderData === null) { + console.error("Cannot render without Splatv object"); + return; + } + + u_focal = gl.getUniformLocation(this.program, "focal") as WebGLUniformLocation; + gl.uniform2fv(u_focal, new Float32Array([this._camera.data.fx, this._camera.data.fy])); + + u_view = gl.getUniformLocation(this.program, "view") as WebGLUniformLocation; + gl.uniformMatrix4fv(u_view, false, this._camera.data.viewMatrix.buffer); + + this._splatTexture = gl.createTexture() as WebGLTexture; + u_texture = gl.getUniformLocation(this.program, "u_texture") as WebGLUniformLocation; + gl.uniform1i(u_texture, 0); + + u_time = gl.getUniformLocation(this.program, "time") as WebGLUniformLocation; + gl.uniform1f(u_time, Math.sin(Date.now() / 1000) / 2 + 1 / 2); + + vertexBuffer = gl.createBuffer() as WebGLBuffer; + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-2, -2, 2, -2, 2, 2, -2, 2]), gl.STATIC_DRAW); + + positionAttribute = gl.getAttribLocation(this.program, "position"); + gl.enableVertexAttribArray(positionAttribute); + gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0); + + indexBuffer = gl.createBuffer() as WebGLBuffer; + indexAttribute = gl.getAttribLocation(this.program, "index"); + gl.enableVertexAttribArray(indexAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + + setupWorker(); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this._splatTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA32UI, + this._renderData.width, + this._renderData.height, + 0, + gl.RGBA_INTEGER, + gl.UNSIGNED_INT, + this._renderData.data, + ); + + const positions = this._renderData.positions; + const dummyTransforms = new Float32Array(new Matrix4().buffer); + const dummyTransformIndices = new Uint32Array(this._renderData.vertexCount); + dummyTransformIndices.fill(0); + worker.postMessage( + { + sortData: { + positions: positions, + transforms: dummyTransforms, + transformIndices: dummyTransformIndices, + vertexCount: this._renderData.vertexCount, + }, + }, + [positions.buffer, dummyTransforms.buffer, dummyTransformIndices.buffer], + ); + }; + + const handleObjectAdded = (event: Event) => { + const e = event as ObjectAddedEvent; + + if (e.object instanceof Splatv) { + if (this._renderData === null) { + this._renderData = e.object.data; + e.object.addEventListener("objectChanged", handleObjectChanged); + } else { + console.warn("Splatv not supported by default RenderProgram. Use VideoRenderProgram instead."); + } + } + + this.dispose(); + }; + + const handleObjectRemoved = (event: Event) => { + const e = event as ObjectRemovedEvent; + + if (e.object instanceof Splatv) { + if (this._renderData === e.object.data) { + this._renderData = null; + e.object.removeEventListener("objectChanged", handleObjectChanged); + } + } + + this.dispose(); + }; + + const handleObjectChanged = (event: Event) => { + const e = event as ObjectChangedEvent; + + if (e.object instanceof Splatv && this._renderData === e.object.data) { + this.dispose(); + } + }; + + this._render = () => { + if (!this._scene || !this._camera) { + console.error("Cannot render without scene and camera"); + return; + } + + if (!this._renderData) { + console.warn("Cannot render without Splatv object"); + return; + } + + this._camera.update(); + worker.postMessage({ viewProj: this._camera.data.viewProj.buffer }); + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.disable(gl.DEPTH_TEST); + gl.enable(gl.BLEND); + gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE); + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + + gl.uniformMatrix4fv(u_projection, false, this._camera.data.projectionMatrix.buffer); + gl.uniformMatrix4fv(u_view, false, this._camera.data.viewMatrix.buffer); + gl.uniform1f(u_time, Math.sin(Date.now() / 1000) / 2 + 1 / 2); + + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this._depthIndex, gl.STATIC_DRAW); + gl.vertexAttribIPointer(indexAttribute, 1, gl.INT, 0, 0); + gl.vertexAttribDivisor(indexAttribute, 1); + + gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this._renderData.vertexCount); + }; + + this._dispose = () => { + if (!this._scene || !this._camera) { + console.error("Cannot dispose without scene and camera"); + return; + } + + this._scene.removeEventListener("objectAdded", handleObjectAdded); + this._scene.removeEventListener("objectRemoved", handleObjectRemoved); + for (const object of this._scene.objects) { + if (object instanceof Splatv) { + if (this._renderData === object.data) { + this._renderData = null; + object.removeEventListener("objectChanged", handleObjectChanged); + } + } + } + + worker?.terminate(); + + gl.deleteTexture(this._splatTexture); + + gl.deleteBuffer(indexBuffer); + gl.deleteBuffer(vertexBuffer); + }; + } + + get renderData(): SplatvData | null { + return this._renderData; + } + + protected _getVertexSource(): string { + return vertexShaderSource; + } + + protected _getFragmentSource(): string { + return fragmentShaderSource; + } +} + +export { VideoRenderProgram }; diff --git a/src/renderers/webgl/utils/DataWorker.ts b/src/renderers/webgl/utils/DataWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..878ec4288fe91fa87904a3cbd8e754a1d638187d --- /dev/null +++ b/src/renderers/webgl/utils/DataWorker.ts @@ -0,0 +1,163 @@ +import loadWasm from "../../../wasm/data"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let wasmModule: any; + +async function initWasm() { + wasmModule = await loadWasm(); +} + +class Splat { + offset: number = 0; + position: Float32Array = new Float32Array(3); + rotation: Float32Array = new Float32Array(4); + scale: Float32Array = new Float32Array(3); + selected: boolean = false; + vertexCount: number = 0; + positions: Float32Array = new Float32Array(0); + rotations: Float32Array = new Float32Array(0); + scales: Float32Array = new Float32Array(0); + colors: Uint8Array = new Uint8Array(0); + selection: Uint8Array = new Uint8Array(0); +} + +let allocatedVertexCount: number = 0; +const updateQueue = new Array(); +let running = false; +let loading = false; + +let positionsPtr: number; +let rotationsPtr: number; +let scalesPtr: number; +let colorsPtr: number; +let selectionPtr: number; +let dataPtr: number; +let worldPositionsPtr: number; +let worldRotationsPtr: number; +let worldScalesPtr: number; + +const pack = async (splat: Splat) => { + while (loading) { + await new Promise((resolve) => setTimeout(resolve, 0)); + } + + if (!wasmModule) { + loading = true; + await initWasm(); + loading = false; + } + + const targetAllocatedVertexCount = Math.pow(2, Math.ceil(Math.log2(splat.vertexCount))); + if (targetAllocatedVertexCount > allocatedVertexCount) { + if (allocatedVertexCount > 0) { + wasmModule._free(positionsPtr); + wasmModule._free(rotationsPtr); + wasmModule._free(scalesPtr); + wasmModule._free(colorsPtr); + wasmModule._free(selectionPtr); + wasmModule._free(dataPtr); + wasmModule._free(worldPositionsPtr); + wasmModule._free(worldRotationsPtr); + wasmModule._free(worldScalesPtr); + } + + allocatedVertexCount = targetAllocatedVertexCount; + + positionsPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); + rotationsPtr = wasmModule._malloc(4 * allocatedVertexCount * 4); + scalesPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); + colorsPtr = wasmModule._malloc(4 * allocatedVertexCount); + selectionPtr = wasmModule._malloc(allocatedVertexCount); + dataPtr = wasmModule._malloc(8 * allocatedVertexCount * 4); + worldPositionsPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); + worldRotationsPtr = wasmModule._malloc(4 * allocatedVertexCount * 4); + worldScalesPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); + } + + wasmModule.HEAPF32.set(splat.positions, positionsPtr / 4); + wasmModule.HEAPF32.set(splat.rotations, rotationsPtr / 4); + wasmModule.HEAPF32.set(splat.scales, scalesPtr / 4); + wasmModule.HEAPU8.set(splat.colors, colorsPtr); + wasmModule.HEAPU8.set(splat.selection, selectionPtr); + + wasmModule._pack( + splat.selected, + splat.vertexCount, + positionsPtr, + rotationsPtr, + scalesPtr, + colorsPtr, + selectionPtr, + dataPtr, + worldPositionsPtr, + worldRotationsPtr, + worldScalesPtr, + ); + + const outData = new Uint32Array(wasmModule.HEAPU32.buffer, dataPtr, splat.vertexCount * 8); + const detachedData = new Uint32Array(outData.slice().buffer); + + const worldPositions = new Float32Array(wasmModule.HEAPF32.buffer, worldPositionsPtr, splat.vertexCount * 3); + const detachedWorldPositions = new Float32Array(worldPositions.slice().buffer); + + const worldRotations = new Float32Array(wasmModule.HEAPF32.buffer, worldRotationsPtr, splat.vertexCount * 4); + const detachedWorldRotations = new Float32Array(worldRotations.slice().buffer); + + const worldScales = new Float32Array(wasmModule.HEAPF32.buffer, worldScalesPtr, splat.vertexCount * 3); + const detachedWorldScales = new Float32Array(worldScales.slice().buffer); + + const response = { + data: detachedData, + worldPositions: detachedWorldPositions, + worldRotations: detachedWorldRotations, + worldScales: detachedWorldScales, + offset: splat.offset, + vertexCount: splat.vertexCount, + positions: splat.positions.buffer, + rotations: splat.rotations.buffer, + scales: splat.scales.buffer, + colors: splat.colors.buffer, + selection: splat.selection.buffer, + }; + + self.postMessage({ response: response }, [ + response.data.buffer, + response.worldPositions.buffer, + response.worldRotations.buffer, + response.worldScales.buffer, + response.positions, + response.rotations, + response.scales, + response.colors, + response.selection, + ]); + + running = false; +}; + +const packThrottled = () => { + if (updateQueue.length === 0) return; + if (!running) { + running = true; + const splat = updateQueue.shift() as Splat; + pack(splat); + setTimeout(() => { + running = false; + packThrottled(); + }, 0); + } +}; + +self.onmessage = (e) => { + if (e.data.splat) { + const splat = e.data.splat as Splat; + for (const [index, existing] of updateQueue.entries()) { + if (existing.offset === splat.offset) { + updateQueue[index] = splat; + return; + } + } + updateQueue.push(splat); + packThrottled(); + } +}; diff --git a/src/renderers/webgl/utils/IntersectionTester.ts b/src/renderers/webgl/utils/IntersectionTester.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e40f662955817d1f104cddfcb13c990f690a5dd --- /dev/null +++ b/src/renderers/webgl/utils/IntersectionTester.ts @@ -0,0 +1,87 @@ +import { Camera } from "../../../cameras/Camera"; +import { Vector3 } from "../../../math/Vector3"; +import { Splat } from "../../../splats/Splat"; +import { RenderProgram } from "../programs/RenderProgram"; +import { Box3 } from "../../../math/Box3"; +import { BVH } from "../../../math/BVH"; +import { RenderData } from "./RenderData"; + +class IntersectionTester { + testPoint: (x: number, y: number) => Splat | null; + + constructor(renderProgram: RenderProgram, maxDistance: number = 100, resolution: number = 1.0) { + let vertexCount = 0; + let bvh: BVH | null = null; + let lookup: Splat[] = []; + + const build = () => { + if (renderProgram.renderData === null) { + console.error("IntersectionTester cannot be called before renderProgram has been initialized"); + return; + } + lookup = []; + const renderData = renderProgram.renderData as RenderData; + const boxes = new Array(renderData.offsets.size); + let i = 0; + const bounds = new Box3( + new Vector3(Infinity, Infinity, Infinity), + new Vector3(-Infinity, -Infinity, -Infinity), + ); + for (const splat of renderData.offsets.keys()) { + const splatBounds = splat.bounds; + boxes[i++] = splatBounds; + bounds.expand(splatBounds.min); + bounds.expand(splatBounds.max); + lookup.push(splat); + } + bounds.permute(); + bvh = new BVH(bounds, boxes); + vertexCount = renderData.vertexCount; + }; + + this.testPoint = (x: number, y: number) => { + if (renderProgram.renderData === null || renderProgram.camera === null) { + console.error("IntersectionTester cannot be called before renderProgram has been initialized"); + return null; + } + + build(); + + if (bvh === null) { + console.error("Failed to build octree for IntersectionTester"); + return null; + } + + const renderData = renderProgram.renderData as RenderData; + const camera = renderProgram.camera as Camera; + + if (vertexCount !== renderData.vertexCount) { + console.warn("IntersectionTester has not been rebuilt since the last render"); + } + + const ray = camera.screenPointToRay(x, y); + for (let x = 0; x < maxDistance; x += resolution) { + const point = camera.position.add(ray.multiply(x)); + const minPoint = new Vector3( + point.x - resolution / 2, + point.y - resolution / 2, + point.z - resolution / 2, + ); + const maxPoint = new Vector3( + point.x + resolution / 2, + point.y + resolution / 2, + point.z + resolution / 2, + ); + const queryBox = new Box3(minPoint, maxPoint); + const points = bvh.queryRange(queryBox); + if (points.length > 0) { + return lookup[points[0]]; + } + } + + return null; + }; + } +} + +export { IntersectionTester }; diff --git a/src/renderers/webgl/utils/RenderData.ts b/src/renderers/webgl/utils/RenderData.ts new file mode 100644 index 0000000000000000000000000000000000000000..c02a709fdf17dba6a56da946fc9197b75764920c --- /dev/null +++ b/src/renderers/webgl/utils/RenderData.ts @@ -0,0 +1,440 @@ +import { Scene } from "../../../core/Scene"; +import { Splat } from "../../../splats/Splat"; +import DataWorker from "web-worker:./DataWorker.ts"; +import loadWasm from "../../../wasm/data"; +import { Matrix4 } from "../../../math/Matrix4"; + +class RenderData { + public dataChanged = false; + public transformsChanged = false; + public colorTransformsChanged = false; + + private _splatIndices: Map; + private _offsets: Map; + private _data: Uint32Array; + private _width: number; + private _height: number; + private _transforms: Float32Array; + private _transformsWidth: number; + private _transformsHeight: number; + private _transformIndices: Uint32Array; + private _transformIndicesWidth: number; + private _transformIndicesHeight: number; + private _colorTransforms: Float32Array; + private _colorTransformsWidth: number; + private _colorTransformsHeight: number; + private _colorTransformIndices: Uint32Array; + private _colorTransformIndicesWidth: number; + private _colorTransformIndicesHeight: number; + private _positions: Float32Array; + private _rotations: Float32Array; + private _scales: Float32Array; + private _vertexCount: number; + private _updating: Set = new Set(); + private _dirty: Set = new Set(); + private _worker: Worker; + + getSplat: (index: number) => Splat | null; + getLocalIndex: (splat: Splat, index: number) => number; + markDirty: (splat: Splat) => void; + rebuild: () => void; + dispose: () => void; + + constructor(scene: Scene) { + let vertexCount = 0; + let splatIndex = 0; + this._splatIndices = new Map(); + this._offsets = new Map(); + const lookup = new Map(); + for (const object of scene.objects) { + if (object instanceof Splat) { + this._splatIndices.set(object, splatIndex); + this._offsets.set(object, vertexCount); + lookup.set(vertexCount, object); + vertexCount += object.data.vertexCount; + splatIndex++; + } + } + + this._vertexCount = vertexCount; + this._width = 2048; + this._height = Math.ceil((2 * this.vertexCount) / this.width); + this._data = new Uint32Array(this.width * this.height * 4); + + this._transformsWidth = 5; + this._transformsHeight = lookup.size; + this._transforms = new Float32Array(this._transformsWidth * this._transformsHeight * 4); + + this._transformIndicesWidth = 1024; + this._transformIndicesHeight = Math.ceil(this.vertexCount / this._transformIndicesWidth); + this._transformIndices = new Uint32Array(this._transformIndicesWidth * this._transformIndicesHeight); + + this._colorTransformsWidth = 4; + this._colorTransformsHeight = 64; + this._colorTransforms = new Float32Array(this._colorTransformsWidth * this._colorTransformsHeight * 4); + this._colorTransforms.fill(0); + this._colorTransforms[0] = 1; + this._colorTransforms[5] = 1; + this._colorTransforms[10] = 1; + this._colorTransforms[15] = 1; + + this._colorTransformIndicesWidth = 1024; + this._colorTransformIndicesHeight = Math.ceil(this.vertexCount / this._colorTransformIndicesWidth); + this._colorTransformIndices = new Uint32Array( + this._colorTransformIndicesWidth * this._colorTransformIndicesHeight, + ); + this.colorTransformIndices.fill(0); + + this._positions = new Float32Array(this.vertexCount * 3); + this._rotations = new Float32Array(this.vertexCount * 4); + this._scales = new Float32Array(this.vertexCount * 3); + + this._worker = new DataWorker(); + + const updateTransform = (splat: Splat) => { + const splatIndex = this._splatIndices.get(splat) as number; + this._transforms.set(splat.transform.buffer, splatIndex * 20); + this._transforms[splatIndex * 20 + 16] = splat.selected ? 1 : 0; + splat.positionChanged = false; + splat.rotationChanged = false; + splat.scaleChanged = false; + splat.selectedChanged = false; + this.transformsChanged = true; + }; + + const updateColorTransforms = () => { + let colorTransformsChanged = false; + for (const splat of this._splatIndices.keys()) { + if (splat.colorTransformChanged) { + colorTransformsChanged = true; + break; + } + } + if (!colorTransformsChanged) { + return; + } + const colorTransformsMap: Matrix4[] = [new Matrix4()]; + this._colorTransformIndices.fill(0); + let i = 1; + for (const splat of this._splatIndices.keys()) { + const offset = this._offsets.get(splat) as number; + for (const colorTransform of splat.colorTransforms) { + if (!colorTransformsMap.includes(colorTransform)) { + colorTransformsMap.push(colorTransform); + i++; + } + } + for (const index of splat.colorTransformsMap.keys()) { + const colorTransformIndex = splat.colorTransformsMap.get(index) as number; + this._colorTransformIndices[index + offset] = colorTransformIndex + i - 1; + } + splat.colorTransformChanged = false; + } + for (let index = 0; index < colorTransformsMap.length; index++) { + const colorTransform = colorTransformsMap[index]; + this._colorTransforms.set(colorTransform.buffer, index * 16); + } + this.colorTransformsChanged = true; + }; + + this._worker.onmessage = (e) => { + if (e.data.response) { + const response = e.data.response; + const splat = lookup.get(response.offset) as Splat; + updateTransform(splat); + updateColorTransforms(); + + const splatIndex = this._splatIndices.get(splat) as number; + for (let i = 0; i < splat.data.vertexCount; i++) { + this._transformIndices[response.offset + i] = splatIndex; + } + + this._data.set(response.data, response.offset * 8); + splat.data.reattach( + response.positions, + response.rotations, + response.scales, + response.colors, + response.selection, + ); + + this._positions.set(response.worldPositions, response.offset * 3); + this._rotations.set(response.worldRotations, response.offset * 4); + this._scales.set(response.worldScales, response.offset * 3); + + this._updating.delete(splat); + + splat.selectedChanged = false; + + this.dataChanged = true; + } + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let wasmModule: any; + + async function initWasm() { + wasmModule = await loadWasm(); + } + + initWasm(); + + async function waitForWasm() { + while (!wasmModule) { + await new Promise((resolve) => setTimeout(resolve, 0)); + } + } + + const buildImmediate = (splat: Splat) => { + if (!wasmModule) { + waitForWasm().then(() => { + buildImmediate(splat); + }); + return; + } + + updateTransform(splat); + + const positionsPtr = wasmModule._malloc(3 * splat.data.vertexCount * 4); + const rotationsPtr = wasmModule._malloc(4 * splat.data.vertexCount * 4); + const scalesPtr = wasmModule._malloc(3 * splat.data.vertexCount * 4); + const colorsPtr = wasmModule._malloc(4 * splat.data.vertexCount); + const selectionPtr = wasmModule._malloc(splat.data.vertexCount); + const dataPtr = wasmModule._malloc(8 * splat.data.vertexCount * 4); + const worldPositionsPtr = wasmModule._malloc(3 * splat.data.vertexCount * 4); + const worldRotationsPtr = wasmModule._malloc(4 * splat.data.vertexCount * 4); + const worldScalesPtr = wasmModule._malloc(3 * splat.data.vertexCount * 4); + + wasmModule.HEAPF32.set(splat.data.positions, positionsPtr / 4); + wasmModule.HEAPF32.set(splat.data.rotations, rotationsPtr / 4); + wasmModule.HEAPF32.set(splat.data.scales, scalesPtr / 4); + wasmModule.HEAPU8.set(splat.data.colors, colorsPtr); + wasmModule.HEAPU8.set(splat.data.selection, selectionPtr); + + wasmModule._pack( + splat.selected, + splat.data.vertexCount, + positionsPtr, + rotationsPtr, + scalesPtr, + colorsPtr, + selectionPtr, + dataPtr, + worldPositionsPtr, + worldRotationsPtr, + worldScalesPtr, + ); + + const outData = new Uint32Array(wasmModule.HEAPU32.buffer, dataPtr, splat.data.vertexCount * 8); + const worldPositions = new Float32Array( + wasmModule.HEAPF32.buffer, + worldPositionsPtr, + splat.data.vertexCount * 3, + ); + const worldRotations = new Float32Array( + wasmModule.HEAPF32.buffer, + worldRotationsPtr, + splat.data.vertexCount * 4, + ); + const worldScales = new Float32Array(wasmModule.HEAPF32.buffer, worldScalesPtr, splat.data.vertexCount * 3); + + const splatIndex = this._splatIndices.get(splat) as number; + const offset = this._offsets.get(splat) as number; + for (let i = 0; i < splat.data.vertexCount; i++) { + this._transformIndices[offset + i] = splatIndex; + } + this._data.set(outData, offset * 8); + this._positions.set(worldPositions, offset * 3); + this._rotations.set(worldRotations, offset * 4); + this._scales.set(worldScales, offset * 3); + + wasmModule._free(positionsPtr); + wasmModule._free(rotationsPtr); + wasmModule._free(scalesPtr); + wasmModule._free(colorsPtr); + wasmModule._free(selectionPtr); + wasmModule._free(dataPtr); + wasmModule._free(worldPositionsPtr); + wasmModule._free(worldRotationsPtr); + wasmModule._free(worldScalesPtr); + + this.dataChanged = true; + this.colorTransformsChanged = true; + }; + + const build = (splat: Splat) => { + if (splat.positionChanged || splat.rotationChanged || splat.scaleChanged || splat.selectedChanged) { + updateTransform(splat); + } + + if (splat.colorTransformChanged) { + updateColorTransforms(); + } + + if (!splat.data.changed || splat.data.detached) return; + + const serializedSplat = { + position: new Float32Array(splat.position.flat()), + rotation: new Float32Array(splat.rotation.flat()), + scale: new Float32Array(splat.scale.flat()), + selected: splat.selected, + vertexCount: splat.data.vertexCount, + positions: splat.data.positions, + rotations: splat.data.rotations, + scales: splat.data.scales, + colors: splat.data.colors, + selection: splat.data.selection, + offset: this._offsets.get(splat) as number, + }; + + this._worker.postMessage( + { + splat: serializedSplat, + }, + [ + serializedSplat.position.buffer, + serializedSplat.rotation.buffer, + serializedSplat.scale.buffer, + serializedSplat.positions.buffer, + serializedSplat.rotations.buffer, + serializedSplat.scales.buffer, + serializedSplat.colors.buffer, + serializedSplat.selection.buffer, + ], + ); + + this._updating.add(splat); + + splat.data.detached = true; + }; + + this.getSplat = (index: number) => { + let splat = null; + for (const [key, value] of this._offsets) { + if (index >= value) { + splat = key; + } else { + break; + } + } + return splat; + }; + + this.getLocalIndex = (splat: Splat, index: number) => { + const offset = this._offsets.get(splat) as number; + return index - offset; + }; + + this.markDirty = (splat: Splat) => { + this._dirty.add(splat); + }; + + this.rebuild = () => { + for (const splat of this._dirty) { + build(splat); + } + + this._dirty.clear(); + }; + + this.dispose = () => { + this._worker.terminate(); + }; + + for (const splat of this._splatIndices.keys()) { + buildImmediate(splat); + } + + updateColorTransforms(); + } + + get offsets() { + return this._offsets; + } + + get data() { + return this._data; + } + + get width() { + return this._width; + } + + get height() { + return this._height; + } + + get transforms() { + return this._transforms; + } + + get transformsWidth() { + return this._transformsWidth; + } + + get transformsHeight() { + return this._transformsHeight; + } + + get transformIndices() { + return this._transformIndices; + } + + get transformIndicesWidth() { + return this._transformIndicesWidth; + } + + get transformIndicesHeight() { + return this._transformIndicesHeight; + } + + get colorTransforms() { + return this._colorTransforms; + } + + get colorTransformsWidth() { + return this._colorTransformsWidth; + } + + get colorTransformsHeight() { + return this._colorTransformsHeight; + } + + get colorTransformIndices() { + return this._colorTransformIndices; + } + + get colorTransformIndicesWidth() { + return this._colorTransformIndicesWidth; + } + + get colorTransformIndicesHeight() { + return this._colorTransformIndicesHeight; + } + + get positions() { + return this._positions; + } + + get rotations() { + return this._rotations; + } + + get scales() { + return this._scales; + } + + get vertexCount() { + return this._vertexCount; + } + + get needsRebuild() { + return this._dirty.size > 0; + } + + get updating() { + return this._updating.size > 0; + } +} + +export { RenderData }; diff --git a/src/renderers/webgl/utils/SortWorker.ts b/src/renderers/webgl/utils/SortWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..afac79190fcc3d9c198f7fbf84a9a85e24d6b03d --- /dev/null +++ b/src/renderers/webgl/utils/SortWorker.ts @@ -0,0 +1,155 @@ +import loadWasm from "../../../wasm/sort"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let wasmModule: any; + +async function initWasm() { + wasmModule = await loadWasm(); +} + +let sortData: { + positions: Float32Array; + transforms: Float32Array; + transformIndices: Uint32Array; + vertexCount: number; +}; + +let viewProjPtr: number; +let transformsPtr: number; +let transformIndicesPtr: number; +let positionsPtr: number; +let depthBufferPtr: number; +let depthIndexPtr: number; +let startsPtr: number; +let countsPtr: number; + +let allocatedVertexCount: number = 0; +let allocatedTransformCount: number = 0; +let viewProj: number[] = []; + +let dirty = true; +let lock = false; +let allocationPending = false; +let sorting = false; + +const allocateBuffers = async () => { + if (lock) { + allocationPending = true; + return; + } + lock = true; + allocationPending = false; + + if (!wasmModule) await initWasm(); + + const targetAllocatedVertexCount = Math.pow(2, Math.ceil(Math.log2(sortData.vertexCount))); + if (allocatedVertexCount < targetAllocatedVertexCount) { + if (allocatedVertexCount > 0) { + wasmModule._free(viewProjPtr); + wasmModule._free(transformIndicesPtr); + wasmModule._free(positionsPtr); + wasmModule._free(depthBufferPtr); + wasmModule._free(depthIndexPtr); + wasmModule._free(startsPtr); + wasmModule._free(countsPtr); + } + + allocatedVertexCount = targetAllocatedVertexCount; + + viewProjPtr = wasmModule._malloc(16 * 4); + transformIndicesPtr = wasmModule._malloc(allocatedVertexCount * 4); + positionsPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); + depthBufferPtr = wasmModule._malloc(allocatedVertexCount * 4); + depthIndexPtr = wasmModule._malloc(allocatedVertexCount * 4); + startsPtr = wasmModule._malloc(allocatedVertexCount * 4); + countsPtr = wasmModule._malloc(allocatedVertexCount * 4); + } + + if (allocatedTransformCount < sortData.transforms.length) { + if (allocatedTransformCount > 0) { + wasmModule._free(transformsPtr); + } + + allocatedTransformCount = sortData.transforms.length; + + transformsPtr = wasmModule._malloc(allocatedTransformCount * 4); + } + + lock = false; + if (allocationPending) { + allocationPending = false; + await allocateBuffers(); + } +}; + +const runSort = () => { + if (lock || allocationPending || !wasmModule) return; + lock = true; + + wasmModule.HEAPF32.set(sortData.positions, positionsPtr / 4); + wasmModule.HEAPF32.set(sortData.transforms, transformsPtr / 4); + wasmModule.HEAPU32.set(sortData.transformIndices, transformIndicesPtr / 4); + wasmModule.HEAPF32.set(new Float32Array(viewProj), viewProjPtr / 4); + + wasmModule._sort( + viewProjPtr, + transformsPtr, + transformIndicesPtr, + sortData.vertexCount, + positionsPtr, + depthBufferPtr, + depthIndexPtr, + startsPtr, + countsPtr, + ); + + const depthIndex = new Uint32Array(wasmModule.HEAPU32.buffer, depthIndexPtr, sortData.vertexCount); + const detachedDepthIndex = new Uint32Array(depthIndex.slice().buffer); + + self.postMessage({ depthIndex: detachedDepthIndex }, [detachedDepthIndex.buffer]); + + lock = false; + dirty = false; +}; + +const throttledSort = () => { + if (!sorting) { + sorting = true; + if (dirty) runSort(); + + setTimeout(() => { + sorting = false; + throttledSort(); + }); + } +}; + +self.onmessage = (e) => { + if (e.data.sortData) { + //Recreating the typed arrays every time, will cause firefox to leak memory + if (!sortData) { + sortData = { + positions: new Float32Array(e.data.sortData.positions), + transforms: new Float32Array(e.data.sortData.transforms), + transformIndices: new Uint32Array(e.data.sortData.transformIndices), + vertexCount: e.data.sortData.vertexCount, + }; + } else { + sortData.positions.set(e.data.sortData.positions); + sortData.transforms.set(e.data.sortData.transforms); + sortData.transformIndices.set(e.data.sortData.transformIndices); + sortData.vertexCount = e.data.sortData.vertexCount; + } + + dirty = true; + allocateBuffers(); + } + if (e.data.viewProj) { + if ((e.data.viewProj as number[]).every((item) => viewProj.includes(item)) === false) { + viewProj = e.data.viewProj; + dirty = true; + } + + throttledSort(); + } +}; diff --git a/src/splats/Splat.ts b/src/splats/Splat.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cc5e7530b65bbb9023456c1b96d00c675fc1bfb --- /dev/null +++ b/src/splats/Splat.ts @@ -0,0 +1,136 @@ +import { SplatData } from "./SplatData"; +import { Object3D } from "../core/Object3D"; +import { Vector3 } from "../math/Vector3"; +import { Quaternion } from "../math/Quaternion"; +import { Converter } from "../utils/Converter"; +import { Matrix4 } from "../math/Matrix4"; +import { Box3 } from "../math/Box3"; + +class Splat extends Object3D { + public selectedChanged: boolean = false; + public colorTransformChanged: boolean = false; + + private _data: SplatData; + private _selected: boolean = false; + private _colorTransforms: Array = []; + private _colorTransformsMap: Map = new Map(); + private _bounds: Box3; + + recalculateBounds: () => void; + + constructor(splat: SplatData | undefined = undefined) { + super(); + + this._data = splat || new SplatData(); + this._bounds = new Box3( + new Vector3(Infinity, Infinity, Infinity), + new Vector3(-Infinity, -Infinity, -Infinity), + ); + + this.recalculateBounds = () => { + this._bounds = new Box3( + new Vector3(Infinity, Infinity, Infinity), + new Vector3(-Infinity, -Infinity, -Infinity), + ); + for (let i = 0; i < this._data.vertexCount; i++) { + this._bounds.expand( + new Vector3( + this._data.positions[3 * i], + this._data.positions[3 * i + 1], + this._data.positions[3 * i + 2], + ), + ); + } + }; + + this.applyPosition = () => { + this.data.translate(this.position); + this.position = new Vector3(); + }; + + this.applyRotation = () => { + this.data.rotate(this.rotation); + this.rotation = new Quaternion(); + }; + + this.applyScale = () => { + this.data.scale(this.scale); + this.scale = new Vector3(1, 1, 1); + }; + + this.recalculateBounds(); + } + + saveToFile(name: string | null = null, format: "splat" | "ply" = "splat") { + if (!document) return; + + if (!name) { + const now = new Date(); + name = `splat-${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}.${format}`; + } + + const splatClone = this.clone(); + + splatClone.applyRotation(); + splatClone.applyScale(); + splatClone.applyPosition(); + + const data = splatClone.data.serialize(); + let blob; + if (format === "ply") { + const plyData = Converter.SplatToPLY(data.buffer, splatClone.data.vertexCount); + blob = new Blob([plyData], { type: "application/octet-stream" }); + } else { + blob = new Blob([data.buffer], { type: "application/octet-stream" }); + } + + const link = document.createElement("a"); + link.download = name; + link.href = URL.createObjectURL(blob); + link.click(); + } + + get data() { + return this._data; + } + + get selected() { + return this._selected; + } + + set selected(selected: boolean) { + if (this._selected !== selected) { + this._selected = selected; + this.selectedChanged = true; + this.dispatchEvent(this._changeEvent); + } + } + + get colorTransforms() { + return this._colorTransforms; + } + + get colorTransformsMap() { + return this._colorTransformsMap; + } + + get bounds() { + let center = this._bounds.center(); + center = center.add(this.position); + + let size = this._bounds.size(); + size = size.multiply(this.scale); + + return new Box3(center.subtract(size.divide(2)), center.add(size.divide(2))); + } + + clone() { + const splat = new Splat(this.data.clone()); + splat.position = this.position.clone(); + splat.rotation = this.rotation.clone(); + splat.scale = this.scale.clone(); + return splat; + } +} + +export { Splat }; diff --git a/src/splats/SplatData.ts b/src/splats/SplatData.ts new file mode 100644 index 0000000000000000000000000000000000000000..046dc4999c151baef937e6311ba5ac275139a67b --- /dev/null +++ b/src/splats/SplatData.ts @@ -0,0 +1,213 @@ +import { Vector3 } from "../math/Vector3"; +import { Quaternion } from "../math/Quaternion"; +import { Matrix3 } from "../math/Matrix3"; + +class SplatData { + static RowLength = 3 * 4 + 3 * 4 + 4 + 4; + + public changed = false; + public detached = false; + + private _vertexCount: number; + private _positions: Float32Array; + private _rotations: Float32Array; + private _scales: Float32Array; + private _colors: Uint8Array; + private _selection: Uint8Array; + + translate: (translation: Vector3) => void; + rotate: (rotation: Quaternion) => void; + scale: (scale: Vector3) => void; + serialize: () => Uint8Array; + reattach: ( + positions: ArrayBufferLike, + rotations: ArrayBufferLike, + scales: ArrayBufferLike, + colors: ArrayBufferLike, + selection: ArrayBufferLike, + ) => void; + + constructor( + vertexCount: number = 0, + positions: Float32Array | null = null, + rotations: Float32Array | null = null, + scales: Float32Array | null = null, + colors: Uint8Array | null = null, + ) { + this._vertexCount = vertexCount; + this._positions = positions || new Float32Array(0); + this._rotations = rotations || new Float32Array(0); + this._scales = scales || new Float32Array(0); + this._colors = colors || new Uint8Array(0); + this._selection = new Uint8Array(this.vertexCount); + + this.translate = (translation: Vector3) => { + for (let i = 0; i < this.vertexCount; i++) { + this.positions[3 * i + 0] += translation.x; + this.positions[3 * i + 1] += translation.y; + this.positions[3 * i + 2] += translation.z; + } + + this.changed = true; + }; + + this.rotate = (rotation: Quaternion) => { + const R = Matrix3.RotationFromQuaternion(rotation).buffer; + for (let i = 0; i < this.vertexCount; i++) { + const x = this.positions[3 * i + 0]; + const y = this.positions[3 * i + 1]; + const z = this.positions[3 * i + 2]; + + this.positions[3 * i + 0] = R[0] * x + R[1] * y + R[2] * z; + this.positions[3 * i + 1] = R[3] * x + R[4] * y + R[5] * z; + this.positions[3 * i + 2] = R[6] * x + R[7] * y + R[8] * z; + + const currentRotation = new Quaternion( + this.rotations[4 * i + 1], + this.rotations[4 * i + 2], + this.rotations[4 * i + 3], + this.rotations[4 * i + 0], + ); + + const newRot = rotation.multiply(currentRotation); + this.rotations[4 * i + 1] = newRot.x; + this.rotations[4 * i + 2] = newRot.y; + this.rotations[4 * i + 3] = newRot.z; + this.rotations[4 * i + 0] = newRot.w; + } + + this.changed = true; + }; + + this.scale = (scale: Vector3) => { + for (let i = 0; i < this.vertexCount; i++) { + this.positions[3 * i + 0] *= scale.x; + this.positions[3 * i + 1] *= scale.y; + this.positions[3 * i + 2] *= scale.z; + + this.scales[3 * i + 0] *= scale.x; + this.scales[3 * i + 1] *= scale.y; + this.scales[3 * i + 2] *= scale.z; + } + + this.changed = true; + }; + + this.serialize = () => { + const data = new Uint8Array(this.vertexCount * SplatData.RowLength); + + const f_buffer = new Float32Array(data.buffer); + const u_buffer = new Uint8Array(data.buffer); + + for (let i = 0; i < this.vertexCount; i++) { + f_buffer[8 * i + 0] = this.positions[3 * i + 0]; + f_buffer[8 * i + 1] = this.positions[3 * i + 1]; + f_buffer[8 * i + 2] = this.positions[3 * i + 2]; + + u_buffer[32 * i + 24 + 0] = this.colors[4 * i + 0]; + u_buffer[32 * i + 24 + 1] = this.colors[4 * i + 1]; + u_buffer[32 * i + 24 + 2] = this.colors[4 * i + 2]; + u_buffer[32 * i + 24 + 3] = this.colors[4 * i + 3]; + + f_buffer[8 * i + 3 + 0] = this.scales[3 * i + 0]; + f_buffer[8 * i + 3 + 1] = this.scales[3 * i + 1]; + f_buffer[8 * i + 3 + 2] = this.scales[3 * i + 2]; + + u_buffer[32 * i + 28 + 0] = (this.rotations[4 * i + 0] * 128 + 128) & 0xff; + u_buffer[32 * i + 28 + 1] = (this.rotations[4 * i + 1] * 128 + 128) & 0xff; + u_buffer[32 * i + 28 + 2] = (this.rotations[4 * i + 2] * 128 + 128) & 0xff; + u_buffer[32 * i + 28 + 3] = (this.rotations[4 * i + 3] * 128 + 128) & 0xff; + } + + return data; + }; + + this.reattach = ( + positions: ArrayBufferLike, + rotations: ArrayBufferLike, + scales: ArrayBufferLike, + colors: ArrayBufferLike, + selection: ArrayBufferLike, + ) => { + console.assert( + positions.byteLength === this.vertexCount * 3 * 4, + `Expected ${this.vertexCount * 3 * 4} bytes, got ${positions.byteLength} bytes`, + ); + this._positions = new Float32Array(positions); + this._rotations = new Float32Array(rotations); + this._scales = new Float32Array(scales); + this._colors = new Uint8Array(colors); + this._selection = new Uint8Array(selection); + this.detached = false; + }; + } + + static Deserialize(data: Uint8Array): SplatData { + const vertexCount = data.length / SplatData.RowLength; + const positions = new Float32Array(3 * vertexCount); + const rotations = new Float32Array(4 * vertexCount); + const scales = new Float32Array(3 * vertexCount); + const colors = new Uint8Array(4 * vertexCount); + + const f_buffer = new Float32Array(data.buffer); + const u_buffer = new Uint8Array(data.buffer); + + for (let i = 0; i < vertexCount; i++) { + positions[3 * i + 0] = f_buffer[8 * i + 0]; + positions[3 * i + 1] = f_buffer[8 * i + 1]; + positions[3 * i + 2] = f_buffer[8 * i + 2]; + + rotations[4 * i + 0] = (u_buffer[32 * i + 28 + 0] - 128) / 128; + rotations[4 * i + 1] = (u_buffer[32 * i + 28 + 1] - 128) / 128; + rotations[4 * i + 2] = (u_buffer[32 * i + 28 + 2] - 128) / 128; + rotations[4 * i + 3] = (u_buffer[32 * i + 28 + 3] - 128) / 128; + + scales[3 * i + 0] = f_buffer[8 * i + 3 + 0]; + scales[3 * i + 1] = f_buffer[8 * i + 3 + 1]; + scales[3 * i + 2] = f_buffer[8 * i + 3 + 2]; + + colors[4 * i + 0] = u_buffer[32 * i + 24 + 0]; + colors[4 * i + 1] = u_buffer[32 * i + 24 + 1]; + colors[4 * i + 2] = u_buffer[32 * i + 24 + 2]; + colors[4 * i + 3] = u_buffer[32 * i + 24 + 3]; + } + + return new SplatData(vertexCount, positions, rotations, scales, colors); + } + + get vertexCount() { + return this._vertexCount; + } + + get positions() { + return this._positions; + } + + get rotations() { + return this._rotations; + } + + get scales() { + return this._scales; + } + + get colors() { + return this._colors; + } + + get selection() { + return this._selection; + } + + clone() { + return new SplatData( + this.vertexCount, + new Float32Array(this.positions), + new Float32Array(this.rotations), + new Float32Array(this.scales), + new Uint8Array(this.colors), + ); + } +} + +export { SplatData }; diff --git a/src/splats/Splatv.ts b/src/splats/Splatv.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c4beb581a12481d811f1deddc46b7dfa004e227 --- /dev/null +++ b/src/splats/Splatv.ts @@ -0,0 +1,18 @@ +import { Object3D } from "../core/Object3D"; +import { SplatvData } from "./SplatvData"; + +class Splatv extends Object3D { + private _data: SplatvData; + + constructor(splat: SplatvData) { + super(); + + this._data = splat; + } + + get data() { + return this._data; + } +} + +export { Splatv }; diff --git a/src/splats/SplatvData.ts b/src/splats/SplatvData.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3ae94f57d488265eb140867994bc370614fcf0f --- /dev/null +++ b/src/splats/SplatvData.ts @@ -0,0 +1,59 @@ +class SplatvData { + static RowLength = 64; + + private _vertexCount: number; + private _positions: Float32Array; + private _data: Uint32Array; + private _width: number; + private _height: number; + + serialize: () => Uint8Array; + + constructor(vertexCount: number, positions: Float32Array, data: Uint32Array, width: number, height: number) { + this._vertexCount = vertexCount; + this._positions = positions; + this._data = data; + this._width = width; + this._height = height; + + this.serialize = () => { + return new Uint8Array(this._data.buffer); + }; + } + + static Deserialize(data: Uint8Array, width: number, height: number): SplatvData { + const buffer = new Uint32Array(data.buffer); + const f_buffer = new Float32Array(data.buffer); + const vertexCount = Math.floor(f_buffer.byteLength / this.RowLength); + const positions = new Float32Array(vertexCount * 3); + for (let i = 0; i < vertexCount; i++) { + positions[3 * i + 0] = f_buffer[16 * i + 0]; + positions[3 * i + 1] = f_buffer[16 * i + 1]; + positions[3 * i + 2] = f_buffer[16 * i + 2]; + positions[3 * i + 0] = f_buffer[16 * i + 3]; + } + return new SplatvData(vertexCount, positions, buffer, width, height); + } + + get vertexCount() { + return this._vertexCount; + } + + get positions() { + return this._positions; + } + + get data() { + return this._data; + } + + get width() { + return this._width; + } + + get height() { + return this._height; + } +} + +export { SplatvData }; diff --git a/src/utils/Converter.ts b/src/utils/Converter.ts new file mode 100644 index 0000000000000000000000000000000000000000..d83051885e78255dd93e94c429453a4adba0d7e7 --- /dev/null +++ b/src/utils/Converter.ts @@ -0,0 +1,96 @@ +import { Quaternion } from "../math/Quaternion"; + +class Converter { + public static SH_C0 = 0.28209479177387814; + + public static SplatToPLY(buffer: ArrayBuffer, vertexCount: number): ArrayBuffer { + let header = "ply\nformat binary_little_endian 1.0\n"; + header += `element vertex ${vertexCount}\n`; + + const properties = ["x", "y", "z", "nx", "ny", "nz", "f_dc_0", "f_dc_1", "f_dc_2"]; + for (let i = 0; i < 45; i++) { + properties.push(`f_rest_${i}`); + } + properties.push("opacity"); + properties.push("scale_0"); + properties.push("scale_1"); + properties.push("scale_2"); + properties.push("rot_0"); + properties.push("rot_1"); + properties.push("rot_2"); + properties.push("rot_3"); + + for (const property of properties) { + header += `property float ${property}\n`; + } + header += "end_header\n"; + + const headerBuffer = new TextEncoder().encode(header); + + const plyRowLength = 4 * 3 + 4 * 3 + 4 * 3 + 4 * 45 + 4 + 4 * 3 + 4 * 4; + const plyLength = vertexCount * plyRowLength; + const output = new DataView(new ArrayBuffer(headerBuffer.length + plyLength)); + new Uint8Array(output.buffer).set(headerBuffer, 0); + + const f_buffer = new Float32Array(buffer); + const u_buffer = new Uint8Array(buffer); + + const offset = headerBuffer.length; + const f_dc_offset = 4 * 3 + 4 * 3; + const opacity_offset = f_dc_offset + 4 * 3 + 4 * 45; + const scale_offset = opacity_offset + 4; + const rot_offset = scale_offset + 4 * 3; + for (let i = 0; i < vertexCount; i++) { + const pos0 = f_buffer[8 * i + 0]; + const pos1 = f_buffer[8 * i + 1]; + const pos2 = f_buffer[8 * i + 2]; + + const f_dc_0 = (u_buffer[32 * i + 24 + 0] / 255 - 0.5) / this.SH_C0; + const f_dc_1 = (u_buffer[32 * i + 24 + 1] / 255 - 0.5) / this.SH_C0; + const f_dc_2 = (u_buffer[32 * i + 24 + 2] / 255 - 0.5) / this.SH_C0; + + const alpha = u_buffer[32 * i + 24 + 3] / 255; + const opacity = Math.log(alpha / (1 - alpha)); + + const scale0 = Math.log(f_buffer[8 * i + 3 + 0]); + const scale1 = Math.log(f_buffer[8 * i + 3 + 1]); + const scale2 = Math.log(f_buffer[8 * i + 3 + 2]); + + let q = new Quaternion( + (u_buffer[32 * i + 28 + 1] - 128) / 128, + (u_buffer[32 * i + 28 + 2] - 128) / 128, + (u_buffer[32 * i + 28 + 3] - 128) / 128, + (u_buffer[32 * i + 28 + 0] - 128) / 128, + ); + q = q.normalize(); + + const rot0 = q.w; + const rot1 = q.x; + const rot2 = q.y; + const rot3 = q.z; + + output.setFloat32(offset + plyRowLength * i + 0, pos0, true); + output.setFloat32(offset + plyRowLength * i + 4, pos1, true); + output.setFloat32(offset + plyRowLength * i + 8, pos2, true); + + output.setFloat32(offset + plyRowLength * i + f_dc_offset + 0, f_dc_0, true); + output.setFloat32(offset + plyRowLength * i + f_dc_offset + 4, f_dc_1, true); + output.setFloat32(offset + plyRowLength * i + f_dc_offset + 8, f_dc_2, true); + + output.setFloat32(offset + plyRowLength * i + opacity_offset, opacity, true); + + output.setFloat32(offset + plyRowLength * i + scale_offset + 0, scale0, true); + output.setFloat32(offset + plyRowLength * i + scale_offset + 4, scale1, true); + output.setFloat32(offset + plyRowLength * i + scale_offset + 8, scale2, true); + + output.setFloat32(offset + plyRowLength * i + rot_offset + 0, rot0, true); + output.setFloat32(offset + plyRowLength * i + rot_offset + 4, rot1, true); + output.setFloat32(offset + plyRowLength * i + rot_offset + 8, rot2, true); + output.setFloat32(offset + plyRowLength * i + rot_offset + 12, rot3, true); + } + + return output.buffer; + } +} + +export { Converter }; diff --git a/src/utils/LoaderUtils.ts b/src/utils/LoaderUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..61693a0c60dbfa2c803dc26e668470d3d9db18f0 --- /dev/null +++ b/src/utils/LoaderUtils.ts @@ -0,0 +1,74 @@ +export async function initiateFetchRequest(url: string, useCache: boolean): Promise { + const req = await fetch(url, { + mode: "cors", + credentials: "omit", + cache: useCache ? "force-cache" : "default", + }); + + if (req.status != 200) { + throw new Error(req.status + " Unable to load " + req.url); + } + + return req; +} + +export async function loadDataIntoBuffer(res: Response, onProgress?: (progress: number) => void): Promise { + const reader = res.body!.getReader(); + + const contentLength = parseInt(res.headers.get("content-length") as string); + const buffer = new Uint8Array(contentLength); + + let bytesRead = 0; + + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer.set(value, bytesRead); + bytesRead += value.length; + onProgress?.(bytesRead / contentLength); + } + + return buffer; +} + +export async function loadChunkedDataIntoBuffer( + res: Response, + onProgress?: (progress: number) => void, +): Promise { + const reader = res.body!.getReader(); + + const chunks = []; + let receivedLength = 0; + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + chunks.push(value); + receivedLength += value.length; + } + + const buffer = new Uint8Array(receivedLength); + let position = 0; + for (const chunk of chunks) { + buffer.set(chunk, position); + position += chunk.length; + + onProgress?.(position / receivedLength); + } + + return buffer; +} + +export async function loadRequestDataIntoBuffer( + res: Response, + onProgress?: (progress: number) => void, +): Promise { + if (res.headers.has("content-length")) { + return loadDataIntoBuffer(res, onProgress); + } else { + return loadChunkedDataIntoBuffer(res, onProgress); + } +} diff --git a/src/wasm/data.d.ts b/src/wasm/data.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..778638c339043302113a7689cc53c7e61829b3b8 --- /dev/null +++ b/src/wasm/data.d.ts @@ -0,0 +1,20 @@ +interface WasmModule { + _malloc(size: number): number; + _free(ptr: number): void; + _pack( + selected: boolean, + vertexCount: number, + positions: number, + rotations: number, + scales: number, + colors: number, + selection: number, + data: number, + worldPositions: number, + worldRotations: number, + worldScales: number, + ): void; +} + +declare const loadWasm: () => Promise; +export default loadWasm; diff --git a/src/wasm/data.js b/src/wasm/data.js new file mode 100644 index 0000000000000000000000000000000000000000..6b32f7778eda222916bd60995e15bc594d3a35f4 --- /dev/null +++ b/src/wasm/data.js @@ -0,0 +1,16 @@ + +var loadWasm = (() => { + var _scriptDir = import.meta.url; + + return ( +function(moduleArg = {}) { + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=true;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected")}function intArrayFromBase64(s){var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;ifilename.startsWith(dataURIPrefix);var wasmBinaryFile;wasmBinaryFile="data:application/octet-stream;base64,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bXNjcmlwdGVuOjptZW1vcnlfdmlldzxzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgc2hvcnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgaW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxmbG9hdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDhfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50OF90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50MTZfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50MTZfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDY0X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDY0X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQzMl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQzMl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBjaGFyPgBzdGQ6OmJhc2ljX3N0cmluZzx1bnNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxzaWduZWQgY2hhcj4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8bG9uZz4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgbG9uZz4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8ZG91YmxlPgBOU3QzX18yMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFRQAAAACkDAAAQgcAAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0loTlNfMTFjaGFyX3RyYWl0c0loRUVOU185YWxsb2NhdG9ySWhFRUVFAACkDAAAjAcAAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0l3TlNfMTFjaGFyX3RyYWl0c0l3RUVOU185YWxsb2NhdG9ySXdFRUVFAACkDAAA1AcAAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0lEc05TXzExY2hhcl90cmFpdHNJRHNFRU5TXzlhbGxvY2F0b3JJRHNFRUVFAAAApAwAABwIAABOU3QzX18yMTJiYXNpY19zdHJpbmdJRGlOU18xMWNoYXJfdHJhaXRzSURpRUVOU185YWxsb2NhdG9ySURpRUVFRQAAAKQMAABoCAAATjEwZW1zY3JpcHRlbjN2YWxFAACkDAAAtAgAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWNFRQAApAwAANAIAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lhRUUAAKQMAAD4CAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJaEVFAACkDAAAIAkAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXNFRQAApAwAAEgJAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0l0RUUAAKQMAABwCQAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJaUVFAACkDAAAmAkAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWpFRQAApAwAAMAJAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lsRUUAAKQMAADoCQAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJbUVFAACkDAAAEAoAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXhFRQAApAwAADgKAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0l5RUUAAKQMAABgCgAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZkVFAACkDAAAiAoAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWRFRQAApAwAALAKAABOMTBfX2N4eGFiaXYxMTZfX3NoaW1fdHlwZV9pbmZvRQAAAADMDAAA2AoAADANAABOMTBfX2N4eGFiaXYxMTdfX2NsYXNzX3R5cGVfaW5mb0UAAADMDAAACAsAAPwKAABOMTBfX2N4eGFiaXYxMTdfX3BiYXNlX3R5cGVfaW5mb0UAAADMDAAAOAsAAPwKAABOMTBfX2N4eGFiaXYxMTlfX3BvaW50ZXJfdHlwZV9pbmZvRQDMDAAAaAsAAFwLAAAAAAAA3AsAAAIAAAADAAAABAAAAAUAAAAGAAAATjEwX19jeHhhYml2MTIzX19mdW5kYW1lbnRhbF90eXBlX2luZm9FAMwMAAC0CwAA/AoAAHYAAACgCwAA6AsAAGIAAACgCwAA9AsAAGMAAACgCwAAAAwAAGgAAACgCwAADAwAAGEAAACgCwAAGAwAAHMAAACgCwAAJAwAAHQAAACgCwAAMAwAAGkAAACgCwAAPAwAAGoAAACgCwAASAwAAGwAAACgCwAAVAwAAG0AAACgCwAAYAwAAHgAAACgCwAAbAwAAHkAAACgCwAAeAwAAGYAAACgCwAAhAwAAGQAAACgCwAAkAwAAAAAAAAsCwAAAgAAAAcAAAAEAAAABQAAAAgAAAAJAAAACgAAAAsAAAAAAAAAFA0AAAIAAAAMAAAABAAAAAUAAAAIAAAADQAAAA4AAAAPAAAATjEwX19jeHhhYml2MTIwX19zaV9jbGFzc190eXBlX2luZm9FAAAAAMwMAADsDAAALAsAAFN0OXR5cGVfaW5mbwAAAACkDAAAIA0AQbgaCwNADwE=";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["k"];updateMemoryViews();addOnInit(wasmExports["l"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};var InternalError;function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":function(pointer){return this["fromWireType"](HEAPU8[pointer])},destructorFunction:null})};function handleAllocatorInit(){Object.assign(HandleAllocator.prototype,{get(id){return this.allocated[id]},has(id){return this.allocated[id]!==undefined},allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id},free(id){this.allocated[id]=undefined;this.freelist.push(id)}})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[]}var emval_handles=new HandleAllocator;var __emval_decref=handle=>{if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}};var count_emval_handles=()=>{var count=0;for(var i=emval_handles.reserved;i{emval_handles.allocated.push({value:undefined},{value:null},{value:true},{value:false});emval_handles.reserved=emval_handles.allocated.length;Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAP32[pointer>>2])}var __embind_register_emval=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":(destructors,value)=>Emval.toHandle(value),"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":value=>value,"toWireType":(destructors,value)=>value,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":floatReadValueFromPointer(name,size),destructorFunction:null})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer>>0]:pointer=>HEAPU8[pointer>>0];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})};function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType"(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>HEAPU16;shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>HEAPU32;shift=2}registerType(rawType,{name:name,"fromWireType":value=>{var length=HEAPU32[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":()=>undefined,"toWireType":(destructors,o)=>undefined})};var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};handleAllocatorInit();init_emval();var wasmImports={f:__embind_register_bigint,i:__embind_register_bool,h:__embind_register_emval,e:__embind_register_float,b:__embind_register_integer,a:__embind_register_memory_view,d:__embind_register_std_string,c:__embind_register_std_wstring,j:__embind_register_void,g:_emscripten_resize_heap};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["l"])();var _pack=Module["_pack"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)=>(_pack=Module["_pack"]=wasmExports["m"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);var ___errno_location=()=>(___errno_location=wasmExports["__errno_location"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["o"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["p"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["__cxa_is_pointer_type"])(a0);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + + + return moduleArg.ready +} +); +})(); +; +export default loadWasm; \ No newline at end of file diff --git a/src/wasm/sort.d.ts b/src/wasm/sort.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5fd3d5ca4910ced5f87f2dcce0e46abc8a72c293 --- /dev/null +++ b/src/wasm/sort.d.ts @@ -0,0 +1,18 @@ +interface WasmModule { + _malloc(size: number): number; + _free(ptr: number): void; + _sort( + viewProj: number, + transforms: number, + transformIndices: number, + vertexCount: number, + positions: number, + depthBuffer: number, + depthIndex: number, + starts: number, + counts: number, + ): void; +} + +declare const loadWasm: () => Promise; +export default loadWasm; diff --git a/src/wasm/sort.js b/src/wasm/sort.js new file mode 100644 index 0000000000000000000000000000000000000000..b7e1b70a5834a84a51862b26ce8aa112f9116b3c --- /dev/null +++ b/src/wasm/sort.js @@ -0,0 +1,16 @@ + +var loadWasm = (() => { + var _scriptDir = import.meta.url; + + return ( +function(moduleArg = {}) { + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=true;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected")}function intArrayFromBase64(s){var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;ifilename.startsWith(dataURIPrefix);var wasmBinaryFile;wasmBinaryFile="data:application/octet-stream;base64,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AWo2AigCQCABKAIkQQFHDQAgASgCGEECRw0AIAFBAToANgsgAUEENgIsCwvyAQAgACABKAIIIAQQCgRAIAEgAiADEBMPCwJAIAAgASgCACAEEAoEQAJAIAIgASgCEEcEQCABKAIUIAJHDQELIANBAUcNAiABQQE2AiAPCyABIAM2AiACQCABKAIsQQRGDQAgAUEAOwE0IAAoAggiACABIAIgAkEBIAQgACgCACgCFBEDACABLQA1BEAgAUEDNgIsIAEtADRFDQEMAwsgAUEENgIsCyABIAI2AhQgASABKAIoQQFqNgIoIAEoAiRBAUcNASABKAIYQQJHDQEgAUEBOgA2DwsgACgCCCIAIAEgAiADIAQgACgCACgCGBECAAsLMQAgACABKAIIQQAQCgRAIAEgAiADEBUPCyAAKAIIIgAgASACIAMgACgCACgCHBEAAAsYACAAIAEoAghBABAKBEAgASACIAMQFQsLgAMBBH8jAEHwAGsiAiQAIAAoAgAiA0EEaygCACEEIANBCGsoAgAhBSACQgA3AlAgAkIANwJYIAJCADcCYCACQgA3AGcgAkIANwJIIAJBADYCRCACQfwVNgJAIAIgADYCPCACIAE2AjggACAFaiEDAkAgBCABQQAQCgRAQQAgAyAFGyEADAELIAAgA04EQCACQgA3AC8gAkIANwIYIAJCADcCICACQgA3AiggAkIANwIQIAJBADYCDCACIAE2AgggAiAANgIEIAIgBDYCACACQQE2AjAgBCACIAMgA0EBQQAgBCgCACgCFBEDACACKAIYDQELQQAhACAEIAJBOGogA0EBQQAgBCgCACgCGBECAAJAAkAgAigCXA4CAAECCyACKAJMQQAgAigCWEEBRhtBACACKAJUQQFGG0EAIAIoAmBBAUYbIQAMAQsgAigCUEEBRwRAIAIoAmANASACKAJUQQFHDQEgAigCWEEBRw0BCyACKAJIIQALIAJB8ABqJAAgAAuaAQECfyMAQUBqIgMkAAJ/QQEgACABQQAQCg0AGkEAIAFFDQAaQQAgAUGsFhAeIgFFDQAaIANBDGpBNBAQGiADQQE2AjggA0F/NgIUIAMgADYCECADIAE2AgggASADQQhqIAIoAgBBASABKAIAKAIcEQAAIAMoAiAiAEEBRgRAIAIgAygCGDYCAAsgAEEBRgshBCADQUBrJAAgBAsKACAAIAFBABAKC/oEAgZ/Cn1B/////wchDEGAgICAeCENQX8hCgNAIAMgC0YEQEEAIQkgCEGAgBAQECEAQwD/f0cgDSAMa7KVIRADQCADIAlGBEBBACEJIAdBADYCACAAQQRrIQBBACEMQQEhCwNAIAtBgIAERkUEQCAHIAtBAnQiAWogACABaigCACAMaiIMNgIAIAtBAWohCwwBCwsDQCADIAlGRQRAIAcgBSAJQQJ0aigCAEECdGoiACAAKAIAIgBBAWo2AgAgBiAAQQJ0aiAJNgIAIAlBAWohCQwBCwsFAn8gECAFIAlBAnRqIgEoAgAgDGuzlCIPQwAAgE9dIA9DAAAAAGBxBEAgD6kMAQtBAAshCyABIAs2AgAgACALQQJ0aiIBIAEoAgBBAWo2AgAgCUEBaiEJDAELCwUgBCALQQxsaiIJKgIAIRMgCSoCCCEUIAkqAgQhFSAKIAIgC0ECdCIOaigCACIJRwRAIAEgCUHQAGxqIgoqAjwgACoCOCIPlCAKKgI4IAAqAigiEJQgCioCMCAAKgIIIhGUIAAqAhgiEiAKKgI0lJKSkiEWIAoqAiwgD5QgCioCKCAQlCAKKgIgIBGUIBIgCioCJJSSkpIhFyAKKgIcIA+UIAoqAhggEJQgCioCECARlCASIAoqAhSUkpKSIRggCioCDCAPlCAKKgIIIBCUIAoqAgAgEZQgCioCBCASlJKSkiEPIAkhCgsgBSAOagJ/IBYgFyAUlCAPIBOUIBUgGJSSkpJDAACARZQiEItDAAAAT10EQCAQqAwBC0GAgICAeAsiCTYCACAMIAkgCSAMShshDCANIAkgCSANSBshDSALQQFqIQsMAQsLCwvHEgIAQYAIC7YSdW5zaWduZWQgc2hvcnQAdW5zaWduZWQgaW50AGZsb2F0AHVpbnQ2NF90AHVuc2lnbmVkIGNoYXIAYm9vbABlbXNjcmlwdGVuOjp2YWwAdW5zaWduZWQgbG9uZwBzdGQ6OndzdHJpbmcAc3RkOjpzdHJpbmcAc3RkOjp1MTZzdHJpbmcAc3RkOjp1MzJzdHJpbmcAZG91YmxlAHZvaWQAZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8c2hvcnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIHNob3J0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGludD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8ZmxvYXQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDhfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDE2X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDE2X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQ2NF90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ2NF90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50MzJfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50MzJfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8Y2hhcj4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgY2hhcj4Ac3RkOjpiYXNpY19zdHJpbmc8dW5zaWduZWQgY2hhcj4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8c2lnbmVkIGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGxvbmc+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGxvbmc+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGRvdWJsZT4ATlN0M19fMjEyYmFzaWNfc3RyaW5nSWNOU18xMWNoYXJfdHJhaXRzSWNFRU5TXzlhbGxvY2F0b3JJY0VFRUUAAAAApAwAAEIHAABOU3QzX18yMTJiYXNpY19zdHJpbmdJaE5TXzExY2hhcl90cmFpdHNJaEVFTlNfOWFsbG9jYXRvckloRUVFRQAApAwAAIwHAABOU3QzX18yMTJiYXNpY19zdHJpbmdJd05TXzExY2hhcl90cmFpdHNJd0VFTlNfOWFsbG9jYXRvckl3RUVFRQAApAwAANQHAABOU3QzX18yMTJiYXNpY19zdHJpbmdJRHNOU18xMWNoYXJfdHJhaXRzSURzRUVOU185YWxsb2NhdG9ySURzRUVFRQAAAKQMAAAcCAAATlN0M19fMjEyYmFzaWNfc3RyaW5nSURpTlNfMTFjaGFyX3RyYWl0c0lEaUVFTlNfOWFsbG9jYXRvcklEaUVFRUUAAACkDAAAaAgAAE4xMGVtc2NyaXB0ZW4zdmFsRQAApAwAALQIAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0ljRUUAAKQMAADQCAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJYUVFAACkDAAA+AgAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWhFRQAApAwAACAJAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lzRUUAAKQMAABICQAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJdEVFAACkDAAAcAkAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWlFRQAApAwAAJgJAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lqRUUAAKQMAADACQAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJbEVFAACkDAAA6AkAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SW1FRQAApAwAABAKAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0l4RUUAAKQMAAA4CgAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJeUVFAACkDAAAYAoAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWZFRQAApAwAAIgKAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lkRUUAAKQMAACwCgAATjEwX19jeHhhYml2MTE2X19zaGltX3R5cGVfaW5mb0UAAAAAzAwAANgKAAAwDQAATjEwX19jeHhhYml2MTE3X19jbGFzc190eXBlX2luZm9FAAAAzAwAAAgLAAD8CgAATjEwX19jeHhhYml2MTE3X19wYmFzZV90eXBlX2luZm9FAAAAzAwAADgLAAD8CgAATjEwX19jeHhhYml2MTE5X19wb2ludGVyX3R5cGVfaW5mb0UAzAwAAGgLAABcCwAAAAAAANwLAAACAAAAAwAAAAQAAAAFAAAABgAAAE4xMF9fY3h4YWJpdjEyM19fZnVuZGFtZW50YWxfdHlwZV9pbmZvRQDMDAAAtAsAAPwKAAB2AAAAoAsAAOgLAABiAAAAoAsAAPQLAABjAAAAoAsAAAAMAABoAAAAoAsAAAwMAABhAAAAoAsAABgMAABzAAAAoAsAACQMAAB0AAAAoAsAADAMAABpAAAAoAsAADwMAABqAAAAoAsAAEgMAABsAAAAoAsAAFQMAABtAAAAoAsAAGAMAAB4AAAAoAsAAGwMAAB5AAAAoAsAAHgMAABmAAAAoAsAAIQMAABkAAAAoAsAAJAMAAAAAAAALAsAAAIAAAAHAAAABAAAAAUAAAAIAAAACQAAAAoAAAALAAAAAAAAABQNAAACAAAADAAAAAQAAAAFAAAACAAAAA0AAAAOAAAADwAAAE4xMF9fY3h4YWJpdjEyMF9fc2lfY2xhc3NfdHlwZV9pbmZvRQAAAADMDAAA7AwAACwLAABTdDl0eXBlX2luZm8AAAAApAwAACANAEG4GgsDQA8B";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["k"];updateMemoryViews();addOnInit(wasmExports["l"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};var InternalError;function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":function(pointer){return this["fromWireType"](HEAPU8[pointer])},destructorFunction:null})};function handleAllocatorInit(){Object.assign(HandleAllocator.prototype,{get(id){return this.allocated[id]},has(id){return this.allocated[id]!==undefined},allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id},free(id){this.allocated[id]=undefined;this.freelist.push(id)}})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[]}var emval_handles=new HandleAllocator;var __emval_decref=handle=>{if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}};var count_emval_handles=()=>{var count=0;for(var i=emval_handles.reserved;i{emval_handles.allocated.push({value:undefined},{value:null},{value:true},{value:false});emval_handles.reserved=emval_handles.allocated.length;Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAP32[pointer>>2])}var __embind_register_emval=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":(destructors,value)=>Emval.toHandle(value),"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":value=>value,"toWireType":(destructors,value)=>value,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":floatReadValueFromPointer(name,size),destructorFunction:null})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer>>0]:pointer=>HEAPU8[pointer>>0];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})};function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType"(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>HEAPU16;shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>HEAPU32;shift=2}registerType(rawType,{name:name,"fromWireType":value=>{var length=HEAPU32[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":()=>undefined,"toWireType":(destructors,o)=>undefined})};var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};handleAllocatorInit();init_emval();var wasmImports={f:__embind_register_bigint,i:__embind_register_bool,h:__embind_register_emval,e:__embind_register_float,b:__embind_register_integer,a:__embind_register_memory_view,d:__embind_register_std_string,c:__embind_register_std_wstring,j:__embind_register_void,g:_emscripten_resize_heap};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["l"])();var _sort=Module["_sort"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(_sort=Module["_sort"]=wasmExports["m"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var ___errno_location=()=>(___errno_location=wasmExports["__errno_location"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["o"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["p"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["__cxa_is_pointer_type"])(a0);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + + + return moduleArg.ready +} +); +})(); +; +export default loadWasm; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..34cef03a74ec3d7c5381436095ac8cad9c62275c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + "target": "ES2019", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "module": "ESNext", /* Specify what module code is generated. */ + "lib": ["ESNext", "WebWorker", "DOM"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["src/**/*"], + "exclude": ["src/wasm/*"] +} diff --git a/wasm/data.cpp b/wasm/data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a179b2c263c5be286446ff5be523cee5a4844c5 --- /dev/null +++ b/wasm/data.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +#include + +uint16_t floatToHalf(float value) { + uint32_t f = *reinterpret_cast(&value); + + uint32_t sign = (f >> 31) & 0x0001; + uint32_t exp = (f >> 23) & 0x00ff; + uint32_t frac = f & 0x007fffff; + + uint32_t newExp; + if (exp == 0) { + newExp = 0; + } else if (exp < 113) { + newExp = 0; + frac |= 0x00800000; + frac >>= (113 - exp); + if (frac & 0x01000000) { + newExp = 1; + frac = 0; + } + } else if (exp < 142) { + newExp = exp - 112; + } else { + newExp = 31; + frac = 0; + } + + return (sign << 15) | (newExp << 10) | (frac >> 13); +} + +uint32_t packHalf2x16(float x, float y) { + uint16_t hx = floatToHalf(x); + uint16_t hy = floatToHalf(y); + return (uint32_t)hx | ((uint32_t)hy << 16); +} + +void multiplyQuaternion(float *a, float *b, float *result) { + result[0] = a[3] * b[1] + a[0] * b[0] + a[1] * b[3] - a[2] * b[2]; + result[1] = a[3] * b[2] - a[0] * b[3] + a[1] * b[0] + a[2] * b[1]; + result[2] = a[3] * b[3] + a[0] * b[2] - a[1] * b[1] + a[2] * b[0]; + result[3] = a[3] * b[0] - a[0] * b[1] - a[1] * b[2] - a[2] * b[3]; +} + +void quaternionToMatrix3(float *q, float *result) { + result[0] = 1 - 2 * q[1] * q[1] - 2 * q[2] * q[2]; + result[1] = 2 * q[0] * q[1] - 2 * q[2] * q[3]; + result[2] = 2 * q[0] * q[2] + 2 * q[1] * q[3]; + result[3] = 2 * q[0] * q[1] + 2 * q[2] * q[3]; + result[4] = 1 - 2 * q[0] * q[0] - 2 * q[2] * q[2]; + result[5] = 2 * q[1] * q[2] - 2 * q[0] * q[3]; + result[6] = 2 * q[0] * q[2] - 2 * q[1] * q[3]; + result[7] = 2 * q[1] * q[2] + 2 * q[0] * q[3]; + result[8] = 1 - 2 * q[0] * q[0] - 2 * q[1] * q[1]; +} + +void multiplyMatrix3(float *a, float *b, float *result) { + result[0] = b[0] * a[0] + b[3] * a[1] + b[6] * a[2]; + result[1] = b[1] * a[0] + b[4] * a[1] + b[7] * a[2]; + result[2] = b[2] * a[0] + b[5] * a[1] + b[8] * a[2]; + result[3] = b[0] * a[3] + b[3] * a[4] + b[6] * a[5]; + result[4] = b[1] * a[3] + b[4] * a[4] + b[7] * a[5]; + result[5] = b[2] * a[3] + b[5] * a[4] + b[8] * a[5]; + result[6] = b[0] * a[6] + b[3] * a[7] + b[6] * a[8]; + result[7] = b[1] * a[6] + b[4] * a[7] + b[7] * a[8]; + result[8] = b[2] * a[6] + b[5] * a[7] + b[8] * a[8]; +} + +extern "C" { +void pack(bool selected, uint32_t vertexCount, float *positions, float *rotations, float *scales, uint8_t *colors, + uint8_t *selection, uint32_t *data, float *worldPositions, float *worldRotations, float *worldScales) { + float rot[4]; + float rotMat[9]; + float scaleMat[9] = {0}; + float M[9]; + float sigma[6]; + + for (uint32_t i = 0; i < vertexCount; i++) { + float x = positions[i * 3 + 0]; + float y = positions[i * 3 + 1]; + float z = positions[i * 3 + 2]; + + worldPositions[i * 3 + 0] = x; + worldPositions[i * 3 + 1] = y; + worldPositions[i * 3 + 2] = z; + + data[8 * i + 0] = *(uint32_t *)&x; + data[8 * i + 1] = *(uint32_t *)&y; + data[8 * i + 2] = *(uint32_t *)&z; + + data[8 * i + 3] = 0; + if (selected || selection[i] > 0) { + data[8 * i + 3] |= 0x01000000; + } + + uint32_t color = 0; + color |= (uint32_t)colors[i * 4 + 0] << 0; + color |= (uint32_t)colors[i * 4 + 1] << 8; + color |= (uint32_t)colors[i * 4 + 2] << 16; + color |= (uint32_t)colors[i * 4 + 3] << 24; + data[8 * i + 7] = color; + + rot[0] = rotations[i * 4 + 1]; + rot[1] = rotations[i * 4 + 2]; + rot[2] = rotations[i * 4 + 3]; + rot[3] = -rotations[i * 4 + 0]; + + quaternionToMatrix3(rot, rotMat); + + worldRotations[i * 4 + 0] = rot[0]; + worldRotations[i * 4 + 1] = rot[1]; + worldRotations[i * 4 + 2] = rot[2]; + worldRotations[i * 4 + 3] = rot[3]; + + scaleMat[0] = scales[i * 3 + 0]; + scaleMat[4] = scales[i * 3 + 1]; + scaleMat[8] = scales[i * 3 + 2]; + + worldScales[i * 3 + 0] = scaleMat[0]; + worldScales[i * 3 + 1] = scaleMat[4]; + worldScales[i * 3 + 2] = scaleMat[8]; + + multiplyMatrix3(scaleMat, rotMat, M); + + sigma[0] = M[0] * M[0] + M[3] * M[3] + M[6] * M[6]; + sigma[1] = M[0] * M[1] + M[3] * M[4] + M[6] * M[7]; + sigma[2] = M[0] * M[2] + M[3] * M[5] + M[6] * M[8]; + sigma[3] = M[1] * M[1] + M[4] * M[4] + M[7] * M[7]; + sigma[4] = M[1] * M[2] + M[4] * M[5] + M[7] * M[8]; + sigma[5] = M[2] * M[2] + M[5] * M[5] + M[8] * M[8]; + + data[8 * i + 4] = packHalf2x16(4 * sigma[0], 4 * sigma[1]); + data[8 * i + 5] = packHalf2x16(4 * sigma[2], 4 * sigma[3]); + data[8 * i + 6] = packHalf2x16(4 * sigma[4], 4 * sigma[5]); + } +} +} \ No newline at end of file diff --git a/wasm/sort.cpp b/wasm/sort.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0f3364bf6e155908679464b1e7899b5b18c1bf6 --- /dev/null +++ b/wasm/sort.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +extern "C" { +void sort(float *viewProj, float *transforms, uint32_t *transformIndices, uint32_t vertexCount, float *positions, + uint32_t *depthBuffer, uint32_t *depthIndex, uint32_t *starts, uint32_t *counts) { + int32_t minDepth = 0x7fffffff; + int32_t maxDepth = 0x80000000; + int32_t previousTransformIndex = -1; + float viewTransform[16]; + for (uint32_t i = 0; i < vertexCount; i++) { + float x = positions[3 * i + 0]; + float y = positions[3 * i + 1]; + float z = positions[3 * i + 2]; + + uint32_t transformIndex = transformIndices[i]; + if (transformIndex != previousTransformIndex) { + previousTransformIndex = transformIndex; + float *transform = &transforms[20 * transformIndex]; + viewTransform[2] = transform[0] * viewProj[2] + transform[1] * viewProj[6] + transform[2] * viewProj[10] + + transform[3] * viewProj[14]; + viewTransform[6] = transform[4] * viewProj[2] + transform[5] * viewProj[6] + transform[6] * viewProj[10] + + transform[7] * viewProj[14]; + viewTransform[10] = transform[8] * viewProj[2] + transform[9] * viewProj[6] + transform[10] * viewProj[10] + + transform[11] * viewProj[14]; + viewTransform[14] = transform[12] * viewProj[2] + transform[13] * viewProj[6] + transform[14] * viewProj[10] + + transform[15] * viewProj[14]; + } + + float projectedZ = viewTransform[2] * x + viewTransform[6] * y + viewTransform[10] * z + viewTransform[14]; + int32_t depth = projectedZ * 4096; + depthBuffer[i] = depth; + if (depth > maxDepth) { + maxDepth = depth; + } + if (depth < minDepth) { + minDepth = depth; + } + } + + const uint32_t depthRange = 256 * 256; + const float depthInv = (float)(depthRange - 1) / (maxDepth - minDepth); + memset(counts, 0, depthRange * sizeof(uint32_t)); + for (uint32_t i = 0; i < vertexCount; i++) { + depthBuffer[i] = (depthBuffer[i] - minDepth) * depthInv; + counts[depthBuffer[i]]++; + } + + starts[0] = 0; + for (uint32_t i = 1; i < depthRange; i++) { + starts[i] = starts[i - 1] + counts[i - 1]; + } + + for (uint32_t i = 0; i < vertexCount; i++) { + depthIndex[starts[depthBuffer[i]]++] = i; + } +} +}