commit 7f7e825992d2503da15e19ddf0489cae5a8554e6 Author: Loi Phan Date: Tue Oct 3 20:54:01 2023 +0700 Init project diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..5c51cad --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +!.*.js +**/dist/** +**/coverage/** diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..663727b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + root: true, + plugins: ['@typescript-eslint', 'import', 'prettier'], + extends: [ + 'airbnb-typescript/base', + 'prettier', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/typescript', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.eslint.json', + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd6ee56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.parcel-cache + +node_modules + +dist \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..1e2b3bf --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +!.*.js +**/dist/** +**/coverage/** +**/package-lock.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..22ca4b4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false +} diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..12e2d47 --- /dev/null +++ b/README.MD @@ -0,0 +1 @@ +typescript-training diff --git a/globals.d.ts b/globals.d.ts new file mode 100644 index 0000000..bff9471 --- /dev/null +++ b/globals.d.ts @@ -0,0 +1 @@ +declare module '*.svg'; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..eaf61b4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7308 @@ +{ + "name": "typescript-practice", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "typescript-practice", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/core-js": "^2.5.6", + "@types/regenerator-runtime": "^0.13.2", + "firebase": "^10.4.0", + "parcel": "^2.9.3" + }, + "devDependencies": { + "@parcel/transformer-sass": "^2.9.3", + "@typescript-eslint/eslint-plugin": "^6.7.3", + "@typescript-eslint/parser": "^6.7.3", + "eslint": "^8.50.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-prettier": "^5.0.0", + "prettier": "^3.0.3", + "process": "^0.11.10", + "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/@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==", + "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==", + "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==", + "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==", + "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==" + }, + "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==", + "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==", + "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==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "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==" + }, + "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==", + "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==", + "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==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.0.tgz", + "integrity": "sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==", + "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.50.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", + "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.0.tgz", + "integrity": "sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.6.tgz", + "integrity": "sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-types": "0.8.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz", + "integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==" + }, + "node_modules/@firebase/app": { + "version": "0.9.19", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.19.tgz", + "integrity": "sha512-t/SHyZ3xWkR77ZU9VMoobDNFLdDKQ5xqoCAn4o16gTsA1C8sJ6ZOMZ02neMOPxNHuQXVE4tA8ukilnDbnK7uJA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.0.tgz", + "integrity": "sha512-dRDnhkcaC2FspMiRK/Vbp+PfsOAEP6ZElGm9iGFJ9fDqHoPs0HOPn7dwpJ51lCFi1+2/7n5pRPGhqF/F03I97g==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.7.tgz", + "integrity": "sha512-cW682AxsyP1G+Z0/P7pO/WT2CzYlNxoNe5QejVarW2o5ZxeWSSPAiVEwpEpQR/bUlUmdeWThYTMvBWaopdBsqw==", + "dependencies": { + "@firebase/app-check": "0.8.0", + "@firebase/app-check-types": "0.5.0", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz", + "integrity": "sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz", + "integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.19", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.19.tgz", + "integrity": "sha512-QkJDqYqjhvs4fTMcRVXQkP9hbo5yfoJXDWkhU4VA5Vzs8Qsp76VPzYbqx5SD5OmBy+bz/Ot1UV8qySPGI4aKuw==", + "dependencies": { + "@firebase/app": "0.9.19", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + }, + "node_modules/@firebase/auth": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.3.0.tgz", + "integrity": "sha512-vjK4CHbY9aWdiVOrKi6mpa8z6uxeaf7LB/MZTHuZOiGHMcUoTGB6TeMbRShyqk1uaMrxhhZ5Ar/dR0965E1qyA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.4.6.tgz", + "integrity": "sha512-pKp1d4fSf+yoy1EBjTx9ISxlunqhW0vTICk0ByZ3e+Lp6ZIXThfUy4F1hAJlEafD/arM0oepRiAh7LXS1xn/BA==", + "dependencies": { + "@firebase/auth": "1.3.0", + "@firebase/auth-types": "0.12.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz", + "integrity": "sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", + "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "dependencies": { + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.1.tgz", + "integrity": "sha512-VAhF7gYwunW4Lw/+RQZvW8dlsf2r0YYqV9W0Gi2Mz8+0TGg1mBJWoUtsHfOr8kPJXhcLsC4eP/z3x6L/Fvjk/A==", + "dependencies": { + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.1.tgz", + "integrity": "sha512-ky82yLIboLxtAIWyW/52a6HLMVTzD2kpZlEilVDok73pNPLjkJYowj8iaIWK5nTy7+6Gxt7d00zfjL6zckGdXQ==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/database": "1.0.1", + "@firebase/database-types": "1.0.0", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.0.tgz", + "integrity": "sha512-SjnXStoE0Q56HcFgNQ+9SsmJc0c8TqGARdI/T44KXy+Ets3r6x/ivhQozT66bMnCEjJRywYoxNurRTMlZF8VNg==", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.2.0.tgz", + "integrity": "sha512-iKZqIdOBJpJUcwY5airLX0W04TLrQSJuActOP1HG5WoIY5oyGTQE4Ml7hl5GW7mBqFieT4ojtUuDXj6MLrn1lA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "@firebase/webchannel-wrapper": "0.10.3", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.18.tgz", + "integrity": "sha512-hkqv4mb1oScKbEtzfcK8Go8c0VpDWmbAvbD6B6XnphLqi27pkXgo9Rp+aSKlD7cBL29VMEekP5bEm9lSVfZpNw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/firestore": "4.2.0", + "@firebase/firestore-types": "3.0.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.0.tgz", + "integrity": "sha512-Meg4cIezHo9zLamw0ymFYBD4SMjLb+ZXIbuN7T7ddXN6MGoICmOTq3/ltdCGoDCS2u+H1XJs2u/cYp75jsX9Qw==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.10.0.tgz", + "integrity": "sha512-2U+fMNxTYhtwSpkkR6WbBcuNMOVaI7MaH3cZ6UAeNfj7AgEwHwMIFLPpC13YNZhno219F0lfxzTAA0N62ndWzA==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.5.tgz", + "integrity": "sha512-uD4jwgwVqdWf6uc3NRKF8cSZ0JwGqSlyhPgackyUPe+GAtnERpS4+Vr66g0b3Gge0ezG4iyHo/EXW/Hjx7QhHw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/functions": "0.10.0", + "@firebase/functions-types": "0.6.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz", + "integrity": "sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==" + }, + "node_modules/@firebase/installations": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.4.tgz", + "integrity": "sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.4.tgz", + "integrity": "sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/installations-types": "0.5.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz", + "integrity": "sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/installations/node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "node_modules/@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.4.tgz", + "integrity": "sha512-6JLZct6zUaex4g7HI3QbzeUrg9xcnmDAPTWpkoMpd/GoSVWH98zDoWXMGrcvHeCAIsLpFMe4MPoZkJbrPhaASw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.4.tgz", + "integrity": "sha512-lyFjeUhIsPRYDPNIkYX1LcZMpoVbBWXX4rPl7c/rqc7G+EUea7IEtSt4MxTvh6fDfPuzLn7+FZADfscC+tNMfg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/messaging": "0.12.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz", + "integrity": "sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==" + }, + "node_modules/@firebase/messaging/node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "node_modules/@firebase/performance": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.4.tgz", + "integrity": "sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.4.tgz", + "integrity": "sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/performance": "0.6.4", + "@firebase/performance-types": "0.2.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz", + "integrity": "sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.4.tgz", + "integrity": "sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz", + "integrity": "sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-types": "0.3.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz", + "integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==" + }, + "node_modules/@firebase/storage": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.11.2.tgz", + "integrity": "sha512-CtvoFaBI4hGXlXbaCHf8humajkbXhs39Nbh6MbNxtwJiCqxPy9iH3D3CCfXAvP0QvAAwmJUTK3+z9a++Kc4nkA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.2.tgz", + "integrity": "sha512-wvsXlLa9DVOMQJckbDNhXKKxRNNewyUhhbXev3t8kSgoCotd1v3MmqhKKz93ePhDnhHnDs7bYHy+Qa8dRY6BXw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/storage": "0.11.2", + "@firebase/storage-types": "0.8.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz", + "integrity": "sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", + "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.3.tgz", + "integrity": "sha512-+ZplYUN3HOpgCfgInqgdDAbkGGVzES1cs32JJpeqoh87SkRobGXElJx+1GZSaDqzFL+bYiX18qEcBK76mYs8uA==" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.4.tgz", + "integrity": "sha512-oEnzYiDuEsBydZBtP84BkpduLsE1nSAO4KrhTLHRzNrIQE647fhchmosTQsJdCo8X9zBBt+l5+fNk+m/yCFJ/Q==", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.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": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@lezer/common": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.1.0.tgz", + "integrity": "sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==" + }, + "node_modules/@lezer/lr": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.12.tgz", + "integrity": "sha512-5nwY1JzCueUdRtlMBnlf1SUi69iGCq2ABq7WQFQMkn/kxPvoACAEnTp4P17CtXxYr7WCwtYPLL2AEvxKPuF1OQ==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@mischnic/json-sourcemap": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", + "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/lr": "^1.0.0", + "json5": "^2.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "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/@parcel/bundler-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.3.tgz", + "integrity": "sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/cache": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.3.tgz", + "integrity": "sha512-Bj/H2uAJJSXtysG7E/x4EgTrE2hXmm7td/bc97K8M9N7+vQjxf7xb0ebgqe84ePVMkj4MVQSMEJkEucXVx4b0Q==", + "dependencies": { + "@parcel/fs": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/utils": "2.9.3", + "lmdb": "2.7.11" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/codeframe": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.3.tgz", + "integrity": "sha512-z7yTyD6h3dvduaFoHpNqur74/2yDWL++33rjQjIjCaXREBN6dKHoMGMizzo/i4vbiI1p9dDox2FIDEHCMQxqdA==", + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/compressor-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.3.tgz", + "integrity": "sha512-jz3t4/ICMsHEqgiTmv5i1DJva2k5QRpZlBELVxfY+QElJTVe8edKJ0TiKcBxh2hx7sm4aUigGmp7JiqqHRRYmA==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/config-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.3.tgz", + "integrity": "sha512-tqN5tF7QnVABDZAu76co5E6N8mA9n8bxiWdK4xYyINYFIEHgX172oRTqXTnhEMjlMrdmASxvnGlbaPBaVnrCTw==", + "dependencies": { + "@parcel/bundler-default": "2.9.3", + "@parcel/compressor-raw": "2.9.3", + "@parcel/namer-default": "2.9.3", + "@parcel/optimizer-css": "2.9.3", + "@parcel/optimizer-htmlnano": "2.9.3", + "@parcel/optimizer-image": "2.9.3", + "@parcel/optimizer-svgo": "2.9.3", + "@parcel/optimizer-swc": "2.9.3", + "@parcel/packager-css": "2.9.3", + "@parcel/packager-html": "2.9.3", + "@parcel/packager-js": "2.9.3", + "@parcel/packager-raw": "2.9.3", + "@parcel/packager-svg": "2.9.3", + "@parcel/reporter-dev-server": "2.9.3", + "@parcel/resolver-default": "2.9.3", + "@parcel/runtime-browser-hmr": "2.9.3", + "@parcel/runtime-js": "2.9.3", + "@parcel/runtime-react-refresh": "2.9.3", + "@parcel/runtime-service-worker": "2.9.3", + "@parcel/transformer-babel": "2.9.3", + "@parcel/transformer-css": "2.9.3", + "@parcel/transformer-html": "2.9.3", + "@parcel/transformer-image": "2.9.3", + "@parcel/transformer-js": "2.9.3", + "@parcel/transformer-json": "2.9.3", + "@parcel/transformer-postcss": "2.9.3", + "@parcel/transformer-posthtml": "2.9.3", + "@parcel/transformer-raw": "2.9.3", + "@parcel/transformer-react-refresh-wrap": "2.9.3", + "@parcel/transformer-svg": "2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/core": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.3.tgz", + "integrity": "sha512-4KlM1Zr/jpsqWuMXr2zmGsaOUs1zMMFh9vfCNKRZkptf+uk8I3sugHbNdo+F5B+4e2yMuOEb1zgAmvJLeuH6ww==", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/profiler": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "abortcontroller-polyfill": "^1.1.9", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/diagnostic": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.3.tgz", + "integrity": "sha512-6jxBdyB3D7gP4iE66ghUGntWt2v64E6EbD4AetZk+hNJpgudOOPsKTovcMi/i7I4V0qD7WXSF4tvkZUoac0jwA==", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/events": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.3.tgz", + "integrity": "sha512-K0Scx+Bx9f9p1vuShMzNwIgiaZUkxEnexaKYHYemJrM7pMAqxIuIqhnvwurRCsZOVLUJPDDNJ626cWTc5vIq+A==", + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/fs": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.3.tgz", + "integrity": "sha512-/PrRKgCRw22G7rNPSpgN3Q+i2nIkZWuvIOAdMG4KWXC4XLp8C9jarNaWd5QEQ75amjhQSl3oUzABzkdCtkKrgg==", + "dependencies": { + "@parcel/fs-search": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/fs-search": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.3.tgz", + "integrity": "sha512-nsNz3bsOpwS+jphcd+XjZL3F3PDq9lik0O8HPm5f6LYkqKWT+u/kgQzA8OkAHCR3q96LGiHxUywHPEBc27vI4Q==", + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/graph": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.3.tgz", + "integrity": "sha512-3LmRJmF8+OprAr6zJT3X2s8WAhLKkrhi6RsFlMWHifGU5ED1PFcJWFbOwJvSjcAhMQJP0fErcFIK1Ludv3Vm3g==", + "dependencies": { + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/hash": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.3.tgz", + "integrity": "sha512-qlH5B85XLzVAeijgKPjm1gQu35LoRYX/8igsjnN8vOlbc3O8BYAUIutU58fbHbtE8MJPbxQQUw7tkTjeoujcQQ==", + "dependencies": { + "xxhash-wasm": "^0.4.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/logger": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.3.tgz", + "integrity": "sha512-5FNBszcV6ilGFcijEOvoNVG6IUJGsnMiaEnGQs7Fvc1dktTjEddnoQbIYhcSZL63wEmzBZOgkT5yDMajJ/41jw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/markdown-ansi": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.3.tgz", + "integrity": "sha512-/Q4X8F2aN8UNjAJrQ5NfK2OmZf6shry9DqetUSEndQ0fHonk78WKt6LT0zSKEBEW/bB/bXk6mNMsCup6L8ibjQ==", + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/namer-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.3.tgz", + "integrity": "sha512-1ynFEcap48/Ngzwwn318eLYpLUwijuuZoXQPCsEQ21OOIOtfhFQJaPwXTsw6kRitshKq76P2aafE0BioGSqxcA==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/node-resolver-core": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.3.tgz", + "integrity": "sha512-AjxNcZVHHJoNT/A99PKIdFtwvoze8PAiC3yz8E/dRggrDIOboUEodeQYV5Aq++aK76uz/iOP0tST2T8A5rhb1A==", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.3.tgz", + "integrity": "sha512-RK1QwcSdWDNUsFvuLy0hgnYKtPQebzCb0vPPzqs6LhL+vqUu9utOyRycGaQffHCkHVQP6zGlN+KFssd7YtFGhA==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.16.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-htmlnano": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.3.tgz", + "integrity": "sha512-9g/KBck3c6DokmJfvJ5zpHFBiCSolaGrcsTGx8C3YPdCTVTI9P1TDCwUxvAr4LjpcIRSa82wlLCI+nF6sSgxKA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "htmlnano": "^2.0.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "svgo": "^2.4.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@parcel/optimizer-image": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.3.tgz", + "integrity": "sha512-530YzthE7kmecnNhPbkAK+26yQNt69pfJrgE0Ev0BZaM1Wu2+33nki7o8qvkTkikhPrurEJLGIXt1qKmbKvCbA==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/optimizer-svgo": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.3.tgz", + "integrity": "sha512-ytQS0wY5JJhWU4mL0wfhYDUuHcfuw+Gy2+JcnTm1t1AZXHlOTbU6EzRWNqBShsgXjvdrQQXizAe3B6GFFlFJVQ==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "svgo": "^2.4.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/@parcel/optimizer-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@parcel/optimizer-swc": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.3.tgz", + "integrity": "sha512-GQINNeqtdpL1ombq/Cpwi6IBk02wKJ/JJbYbyfHtk8lxlq13soenpwOlzJ5T9D2fdG+FUhai9NxpN5Ss4lNoAg==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/package-manager": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.3.tgz", + "integrity": "sha512-NH6omcNTEupDmW4Lm1e4NUYBjdqkURxgZ4CNESESInHJe6tblVhNB8Rpr1ar7zDar7cly9ILr8P6N3Ei7bTEjg==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/node-resolver-core": "3.0.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/packager-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.3.tgz", + "integrity": "sha512-mePiWiYZOULY6e1RdAIJyRoYqXqGci0srOaVZYaP7mnrzvJgA63kaZFFsDiEWghunQpMUuUjM2x/vQVHzxmhKQ==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-html": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.3.tgz", + "integrity": "sha512-0Ex+O0EaZf9APNERRNGgGto02hFJ6f5RQEvRWBK55WAV1rXeU+kpjC0c0qZvnUaUtXfpWMsEBkevJCwDkUMeMg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.3.tgz", + "integrity": "sha512-V5xwkoE3zQ3R+WqAWhA1KGQ791FvJeW6KonOlMI1q76Djjgox68hhObqcLu66AmYNhR2R/wUpkP18hP2z8dSFw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "globals": "^13.2.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.3.tgz", + "integrity": "sha512-oPQTNoYanQ2DdJyL61uPYK2py83rKOT8YVh2QWAx0zsSli6Kiy64U3+xOCYWgDVCrHw9+9NpQMuAdSiFg4cq8g==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-svg": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.3.tgz", + "integrity": "sha512-p/Ya6UO9DAkaCUFxfFGyeHZDp9YPAlpdnh1OChuwqSFOXFjjeXuoK4KLT+ZRalVBo2Jo8xF70oKMZw4MVvaL7Q==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "posthtml": "^0.16.4" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/plugin": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.3.tgz", + "integrity": "sha512-qN85Gqr2GMuxX1dT1mnuO9hOcvlEv1lrYrCxn7CJN2nUhbwcfG+LEvcrCzCOJ6XtIHm+ZBV9h9p7FfoPLvpw+g==", + "dependencies": { + "@parcel/types": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/profiler": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.3.tgz", + "integrity": "sha512-pyHc9lw8VZDfgZoeZWZU9J0CVEv1Zw9O5+e0DJPDPHuXJYr72ZAOhbljtU3owWKAeW+++Q2AZWkbUGEOjI/e6g==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "chrome-trace-event": "^1.0.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-cli": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.3.tgz", + "integrity": "sha512-pZiEvQpuXFuQBafMHxkDmwH8CnnK9sWHwa3bSbsnt385aUahtE8dpY0LKt+K1zfB6degKoczN6aWVj9WycQuZQ==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "chalk": "^4.1.0", + "term-size": "^2.2.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-dev-server": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.3.tgz", + "integrity": "sha512-s6eboxdLEtRSvG52xi9IiNbcPKC0XMVmvTckieue2EqGDbDcaHQoHmmwkk0rNq0/Z/UxelGcQXoIYC/0xq3ykQ==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-tracer": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.3.tgz", + "integrity": "sha512-9cXpKWk0m6d6d+4+TlAdOe8XIPaFEIKGWMWG+5SFAQE08u3olet4PSvd49F4+ZZo5ftRE7YI3j6xNbXvJT8KGw==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/resolver-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.3.tgz", + "integrity": "sha512-8ESJk1COKvDzkmOnppNXoDamNMlYVIvrKc2RuFPmp8nKVj47R6NwMgvwxEaatyPzvkmyTpq5RvG9I3HFc+r4Cw==", + "dependencies": { + "@parcel/node-resolver-core": "3.0.3", + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-browser-hmr": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.3.tgz", + "integrity": "sha512-EgiDIDrVAWpz7bOzWXqVinQkaFjLwT34wsonpXAbuI7f7r00d52vNAQC9AMu+pTijA3gyKoJ+Q4NWPMZf7ACDA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.3.tgz", + "integrity": "sha512-EvIy+qXcKnB5qxHhe96zmJpSAViNVXHfQI5RSdZ2a7CPwORwhTI+zPNT9sb7xb/WwFw/WuTTgzT40b41DceU6Q==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-react-refresh": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.3.tgz", + "integrity": "sha512-XBgryZQIyCmi6JwEfMUCmINB3l1TpTp9a2iFxmYNpzHlqj4Ve0saKaqWOVRLvC945ZovWIBzcSW2IYqWKGtbAA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "react-error-overlay": "6.0.9", + "react-refresh": "^0.9.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-service-worker": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.3.tgz", + "integrity": "sha512-qLJLqv1mMdWL7gyh8aKBFFAuEiJkhUUgLKpdn6eSfH/R7kTtb76WnOwqUrhvEI9bZFUM/8Pa1bzJnPpqSOM+Sw==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/source-map": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", + "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": "^12.18.3 || >=14" + } + }, + "node_modules/@parcel/transformer-babel": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.3.tgz", + "integrity": "sha512-pURtEsnsp3h6tOBDuzh9wRvVtw4PgIlqwAArIWdrG7iwqOUYv9D8ME4+ePWEu7MQWAp58hv9pTJtqWv4T+Sq8A==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "json5": "^2.2.0", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.3.tgz", + "integrity": "sha512-duWMdbEBBPjg3fQdXF16iWIdThetDZvCs2TpUD7xOlXH6kR0V5BJy8ONFT15u1RCqIV9hSNGaS3v3I9YRNY5zQ==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.16.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-html": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.3.tgz", + "integrity": "sha512-0NU4omcHzFXA1seqftAXA2KNZaMByoKaNdXnLgBgtCGDiYvOcL+6xGHgY6pw9LvOh5um10KI5TxSIMILoI7VtA==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2", + "srcset": "4" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-image": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.3.tgz", + "integrity": "sha512-7CEe35RaPadQzLIuxzTtIxnItvOoy46hcbXtOdDt6lmVa4omuOygZYRIya2lsGIP4JHvAaALMb5nt99a1uTwJg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/transformer-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.3.tgz", + "integrity": "sha512-Z2MVVg5FYcPOfxlUwxqb5l9yjTMEqE3KI3zq2MBRUme6AV07KxLmCDF23b6glzZlHWQUE8MXzYCTAkOPCcPz+Q==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "@swc/helpers": "^0.5.0", + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1", + "regenerator-runtime": "^0.13.7", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/transformer-json": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.3.tgz", + "integrity": "sha512-yNL27dbOLhkkrjaQjiQ7Im9VOxmkfuuSNSmS0rA3gEjVcm07SLKRzWkAaPnyx44Lb6bzyOTWwVrb9aMmxgADpA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "json5": "^2.2.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-postcss": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.3.tgz", + "integrity": "sha512-HoDvPqKzhpmvMmHqQhDnt8F1vH61m6plpGiYaYnYv2Om4HHi5ZIq9bO+9QLBnTKfaZ7ndYSefTKOxTYElg7wyw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "clone": "^2.1.1", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-posthtml": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.3.tgz", + "integrity": "sha512-2fQGgrzRmaqbWf3y2/T6xhqrNjzqMMKksqJzvc8TMfK6f2kg3Ddjv158eaSW2JdkV39aY7tvAOn5f1uzo74BMA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.3.tgz", + "integrity": "sha512-oqdPzMC9QzWRbY9J6TZEqltknjno+dY24QWqf8ondmdF2+W+/2mRDu59hhCzQrqUHgTq4FewowRZmSfpzHxwaQ==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-react-refresh-wrap": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.3.tgz", + "integrity": "sha512-cb9NyU6oJlDblFIlzqIE8AkvRQVGl2IwJNKwD4PdE7Y6sq2okGEPG4hOw3k/Y9JVjM4/2pUORqvjSRhWwd9oVQ==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "react-refresh": "^0.9.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-sass": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-sass/-/transformer-sass-2.9.3.tgz", + "integrity": "sha512-i9abj9bKg3xCHghJyTM3rUVxIEn9n1Rl+DFdpyNAD8VZ52COfOshFDQOWNuhU1hEnJOFYCjnfcO0HRTsg3dWmg==", + "dev": true, + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "sass": "^1.38.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-svg": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.3.tgz", + "integrity": "sha512-ypmE+dzB09IMCdEAkOsSxq1dEIm2A3h67nAFz4qbfHbwNgXBUuy/jB3ZMwXN/cO0f7SBh/Ap8Jhq6vmGqB5tWw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/types": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.3.tgz", + "integrity": "sha512-NSNY8sYtRhvF1SqhnIGgGvJocyWt1K8Tnw5cVepm0g38ywtX6mwkBvMkmeehXkII4mSUn+frD9wGsydTunezvA==", + "dependencies": { + "@parcel/cache": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/workers": "2.9.3", + "utility-types": "^3.10.0" + } + }, + "node_modules/@parcel/utils": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.3.tgz", + "integrity": "sha512-cesanjtj/oLehW8Waq9JFPmAImhoiHX03ihc3JTWkrvJYSbD7wYKCDgPAM3JiRAqvh1LZ6P699uITrYWNoRLUg==", + "dependencies": { + "@parcel/codeframe": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/markdown-ansi": "2.9.3", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", + "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.3.0", + "@parcel/watcher-darwin-arm64": "2.3.0", + "@parcel/watcher-darwin-x64": "2.3.0", + "@parcel/watcher-freebsd-x64": "2.3.0", + "@parcel/watcher-linux-arm-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-musl": "2.3.0", + "@parcel/watcher-linux-x64-glibc": "2.3.0", + "@parcel/watcher-linux-x64-musl": "2.3.0", + "@parcel/watcher-win32-arm64": "2.3.0", + "@parcel/watcher-win32-ia32": "2.3.0", + "@parcel/watcher-win32-x64": "2.3.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", + "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", + "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", + "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", + "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", + "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", + "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", + "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", + "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", + "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", + "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", + "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", + "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/workers": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.3.tgz", + "integrity": "sha512-zRrDuZJzTevrrwElYosFztgldhqW6G9q5zOeQXfVQFkkEJCNfg36ixeiofKRU8uu2x+j+T6216mhMNB6HiuY+w==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/profiler": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "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/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@swc/core": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.90.tgz", + "integrity": "sha512-wptBxP4PldOnhmyDVj8qUcn++GRqyw1qc9wOTGtPNHz8cpuTfdfIgYGlhI4La0UYqecuaaIfLfokyuNePOMHPg==", + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.90", + "@swc/core-darwin-x64": "1.3.90", + "@swc/core-linux-arm-gnueabihf": "1.3.90", + "@swc/core-linux-arm64-gnu": "1.3.90", + "@swc/core-linux-arm64-musl": "1.3.90", + "@swc/core-linux-x64-gnu": "1.3.90", + "@swc/core-linux-x64-musl": "1.3.90", + "@swc/core-win32-arm64-msvc": "1.3.90", + "@swc/core-win32-ia32-msvc": "1.3.90", + "@swc/core-win32-x64-msvc": "1.3.90" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.90.tgz", + "integrity": "sha512-he0w74HvcoufE6CZrB/U/VGVbc7021IQvYrn1geMACnq/OqMBqjdczNtdNfJAy87LZ4AOUjHDKEIjsZZu7o8nQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.90.tgz", + "integrity": "sha512-hKNM0Ix0qMlAamPe0HUfaAhQVbZEL5uK6Iw8v9ew0FtVB4v7EifQ9n41wh+yCj0CjcHBPEBbQU0P6mNTxJu/RQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.90.tgz", + "integrity": "sha512-HumvtrqTWE8rlFuKt7If0ZL7145H/jVc4AeziVjcd+/ajpqub7IyfrLCYd5PmKMtfeSVDMsxjG0BJ0HLRxrTJA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.90.tgz", + "integrity": "sha512-tA7DqCS7YCwngwXZQeqQhhMm8BbydpaABw8Z/EDQ7KPK1iZ1rNjZw+aWvSpmNmEGmH1RmQ9QDS9mGRDp0faAeg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.90.tgz", + "integrity": "sha512-p2Vtid5BZA36fJkNUwk5HP+HJlKgTru+Ghna7pRe45ghKkkRIUk3fhkgudEvfKfhT+3AvP+GTVQ+T9k0gc9S8w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.90.tgz", + "integrity": "sha512-J6pDtWaulYGXuANERuvv4CqmUbZOQrRZBCRQGZQJ6a86RWpesZqckBelnYx48wYmkgvMkF95Y3xbI3WTfoSHzw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.90.tgz", + "integrity": "sha512-3Gh6EA3+0K+l3MqnRON7h5bZ32xLmfcVM6QiHHJ9dBttq7YOEeEoMOCdIPMaQxJmK1VfLgZCsPYRd66MhvUSkw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.90.tgz", + "integrity": "sha512-BNaw/iJloDyaNOFV23Sr53ULlnbmzSoerTJ10v0TjSZOEIpsS0Rw6xOK1iI0voDJnRXeZeWRSxEC9DhefNtN/g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.90.tgz", + "integrity": "sha512-SiyTethWAheE/JbxXCukAAciU//PLcmVZ2ME92MRuLMLmOhrwksjbaa7ukj9WEF3LWrherhSqTXnpj3VC1l/qw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.90", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.90.tgz", + "integrity": "sha512-OpWAW5ljKcPJ3SQ0pUuKqYfwXv7ssIhVgrH9XP9ONtdgXKWZRL9hqJQkcL55FARw/gDjKanoCM47wsTNQL+ZZA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.1.tgz", + "integrity": "sha512-xVRaR4u9hcYjFvcSg71Lz5Bo4//CyjAAfMxa7UsaDSYxAshflUkVJWiyVWrfxC59z2kP1IzI4/1BEpnhI9o3Mw==" + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/core-js": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-2.5.6.tgz", + "integrity": "sha512-zLzoC7avO4EYUUYCSzDaahSP1QJEpZQcPxqs91mPeFdh2NS4hQBcnRoEc9RuXfJ8cdN/KXUWukMmZGcKaWeOvw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", + "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==" + }, + "node_modules/@types/regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@types/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-SIYCe4xgq4FSs00vENNHC+L1jxRdN4IKV2abqTu2kb2WkXlPBOml7NK2eCcYdUbQtD8cOWTcBUiYstoiaSNawA==" + }, + "node_modules/@types/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz", + "integrity": "sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.3", + "@typescript-eslint/type-utils": "6.7.3", + "@typescript-eslint/utils": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", + "integrity": "sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.7.3", + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/typescript-estree": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", + "integrity": "sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3" + }, + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz", + "integrity": "sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.7.3", + "@typescript-eslint/utils": "6.7.3", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.3.tgz", + "integrity": "sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz", + "integrity": "sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/visitor-keys": "6.7.3", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.3.tgz", + "integrity": "sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==", + "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.7.3", + "@typescript-eslint/types": "6.7.3", + "@typescript-eslint/typescript-estree": "6.7.3", + "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.7.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz", + "integrity": "sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.7.3", + "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/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "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==", + "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==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "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==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.0.tgz", + "integrity": "sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA==", + "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.30001539", + "electron-to-chromium": "^1.4.530", + "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/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/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001541", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz", + "integrity": "sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==", + "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==", + "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/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "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==", + "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==" + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "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/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "optional": true, + "peer": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "optional": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "optional": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "optional": true, + "peer": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/css-select/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "optional": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "optional": true, + "peer": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "optional": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "optional": true, + "peer": true + }, + "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/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/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-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "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/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.534", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.534.tgz", + "integrity": "sha512-ikY7wAMtMt3jTnHsHG0YLl4MKJiKz2tgidenGSNgwUX2StBLNZ8VCxflD9tZK/ceTs4j8gDC9+6LQQ6iGkK04g==" + }, + "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==" + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", + "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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.50.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", + "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.50.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "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-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/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/eslint-config-airbnb-typescript": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, + "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-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", + "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/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/eslint-plugin-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "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/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/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/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/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "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==", + "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/firebase": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.4.0.tgz", + "integrity": "sha512-3Z8WsNwA7kbcKGZ+nrTZ/ES518pk0K440ZJYD8nUNKN5hV6ll+unhUw30t1msedN6yIFjhsC/9OwT4Z0ohwO2w==", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-compat": "0.2.6", + "@firebase/app": "0.9.19", + "@firebase/app-check": "0.8.0", + "@firebase/app-check-compat": "0.3.7", + "@firebase/app-compat": "0.2.19", + "@firebase/app-types": "0.9.0", + "@firebase/auth": "1.3.0", + "@firebase/auth-compat": "0.4.6", + "@firebase/database": "1.0.1", + "@firebase/database-compat": "1.0.1", + "@firebase/firestore": "4.2.0", + "@firebase/firestore-compat": "0.3.18", + "@firebase/functions": "0.10.0", + "@firebase/functions-compat": "0.3.5", + "@firebase/installations": "0.6.4", + "@firebase/installations-compat": "0.2.4", + "@firebase/messaging": "0.12.4", + "@firebase/messaging-compat": "0.2.4", + "@firebase/performance": "0.6.4", + "@firebase/performance-compat": "0.2.4", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-compat": "0.2.4", + "@firebase/storage": "0.11.2", + "@firebase/storage-compat": "0.3.2", + "@firebase/util": "1.9.3" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "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/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/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.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", + "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", + "engines": { + "node": ">=6" + } + }, + "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/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/htmlnano": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.4.tgz", + "integrity": "sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==", + "dependencies": { + "cosmiconfig": "^8.0.0", + "posthtml": "^0.16.5", + "timsort": "^0.3.0" + }, + "peerDependencies": { + "cssnano": "^6.0.0", + "postcss": "^8.3.11", + "purgecss": "^5.0.0", + "relateurl": "^0.2.7", + "srcset": "4.0.0", + "svgo": "^3.0.2", + "terser": "^5.10.0", + "uncss": "^0.17.3" + }, + "peerDependenciesMeta": { + "cssnano": { + "optional": true + }, + "postcss": { + "optional": true + }, + "purgecss": { + "optional": true + }, + "relateurl": { + "optional": true + }, + "srcset": { + "optional": true + }, + "svgo": { + "optional": true + }, + "terser": { + "optional": true + }, + "uncss": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "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/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "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/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "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==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/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/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "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==", + "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-json": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", + "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==" + }, + "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==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.22.0.tgz", + "integrity": "sha512-+z0qvwRVzs4XGRXelnWRNwqsXUx8k3bSkbP8vD42kYKSk3z9OM2P3e/gagT7ei/gwh8DTS80LZOFZV6lm8Z8Fg==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.22.0", + "lightningcss-darwin-x64": "1.22.0", + "lightningcss-freebsd-x64": "1.22.0", + "lightningcss-linux-arm-gnueabihf": "1.22.0", + "lightningcss-linux-arm64-gnu": "1.22.0", + "lightningcss-linux-arm64-musl": "1.22.0", + "lightningcss-linux-x64-gnu": "1.22.0", + "lightningcss-linux-x64-musl": "1.22.0", + "lightningcss-win32-x64-msvc": "1.22.0" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.22.0.tgz", + "integrity": "sha512-aH2be3nNny+It5YEVm8tBSSdRlBVWQV8m2oJ7dESiYRzyY/E/bQUe2xlw5caaMuhlM9aoTMtOH25yzMhir0qPg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.22.0.tgz", + "integrity": "sha512-9KHRFA0Y6mNxRHeoQMp0YaI0R0O2kOgUlYPRjuasU4d+pI8NRhVn9bt0yX9VPs5ibWX1RbDViSPtGJvYYrfVAQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.22.0.tgz", + "integrity": "sha512-xaYL3xperGwD85rQioDb52ozF3NAJb+9wrge3jD9lxGffplu0Mn35rXMptB8Uc2N9Mw1i3Bvl7+z1evlqVl7ww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.22.0.tgz", + "integrity": "sha512-epQGvXIjOuxrZpMpMnRjK54ZqzhiHhCPLtHvw2fb6NeK2kK9YtF0wqmeTBiQ1AkbWfnnXGTstYaFNiadNK+StQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.22.0.tgz", + "integrity": "sha512-AArGtKSY4DGTA8xP8SDyNyKtpsUl1Rzq6FW4JomeyUQ4nBrR71uPChksTpj3gmWuGhZeRKLeCUI1DBid/zhChg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.22.0.tgz", + "integrity": "sha512-RRraNgP8hnBPhInTTUdlFm+z16C/ghbxBG51Sw00hd7HUyKmEUKRozyc5od+/N6pOrX/bIh5vIbtMXIxsos0lg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.22.0.tgz", + "integrity": "sha512-grdrhYGRi2KrR+bsXJVI0myRADqyA7ekprGxiuK5QRNkv7kj3Yq1fERDNyzZvjisHwKUi29sYMClscbtl+/Zpw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.22.0.tgz", + "integrity": "sha512-t5f90X+iQUtIyR56oXIHMBUyQFX/zwmPt72E6Dane3P8KNGlkijTg2I75XVQS860gNoEFzV7Mm5ArRRA7u5CAQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.22.0.tgz", + "integrity": "sha512-64HTDtOOZE9PUCZJiZZQpyqXBbdby1lnztBccnqh+NtbKxjnGzP92R2ngcgeuqMPecMNqNWxgoWgTGpC+yN5Sw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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==" + }, + "node_modules/lmdb": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", + "hasInstallScript": true, + "dependencies": { + "msgpackr": "1.8.5", + "node-addon-api": "^4.3.0", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11" + } + }, + "node_modules/lmdb/node_modules/msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.1" + } + }, + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "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.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "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/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "optional": true, + "peer": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/msgpackr": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.9.tgz", + "integrity": "sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "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==" + }, + "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/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/ordered-binary": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.4.1.tgz", + "integrity": "sha512-9LtiGlPy982CsgxZvJGNNp2/NnrgEr6EAyN3iIEP3/8vd3YLgAZQHbQ75ZrkfBRGrNg37Dk3U6tuVb+B4Xfslg==" + }, + "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/parcel": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.3.tgz", + "integrity": "sha512-2GTVocFkwblV/TIg9AmT7TI2fO4xdWkyN8aFUEVtiVNWt96GTR3FgQyHFValfCbcj1k9Xf962Ws2hYXYUr9k1Q==", + "dependencies": { + "@parcel/config-default": "2.9.3", + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/reporter-cli": "2.9.3", + "@parcel/reporter-dev-server": "2.9.3", + "@parcel/reporter-tracer": "2.9.3", + "@parcel/utils": "2.9.3", + "chalk": "^4.1.0", + "commander": "^7.0.0", + "get-port": "^4.2.0" + }, + "bin": { + "parcel": "lib/bin.js" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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==", + "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==", + "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==", + "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==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/posthtml": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", + "dependencies": { + "posthtml-parser": "^0.11.0", + "posthtml-render": "^3.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/posthtml-parser": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", + "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/posthtml-render": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", + "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", + "dependencies": { + "is-json": "^2.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/posthtml/node_modules/posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" + }, + "node_modules/react-refresh": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", + "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "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-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-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-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sass": { + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz", + "integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "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==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "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/svgo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "optional": true, + "peer": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "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/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==" + }, + "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/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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "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/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "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-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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "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/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "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/xxhash-wasm": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz", + "integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "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==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "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==", + "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 0000000..6a0a413 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "typescript-practice", + "version": "1.0.0", + "description": "", + "scripts": { + "start": "parcel src/pages/*.html", + "build": "parcel build ./src/pages/*.html --no-cache --no-source-maps --dist-dir dist" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@types/core-js": "^2.5.6", + "@types/regenerator-runtime": "^0.13.2", + "firebase": "^10.4.0", + "parcel": "^2.9.3" + }, + "devDependencies": { + "@parcel/transformer-sass": "^2.9.3", + "@typescript-eslint/eslint-plugin": "^6.7.3", + "@typescript-eslint/parser": "^6.7.3", + "eslint": "^8.50.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-prettier": "^5.0.0", + "prettier": "^3.0.3", + "process": "^0.11.10", + "typescript": "^5.2.2" + } +} diff --git a/src/assets/fonts/roboto-bold.ttf b/src/assets/fonts/roboto-bold.ttf new file mode 100644 index 0000000..43da14d Binary files /dev/null and b/src/assets/fonts/roboto-bold.ttf differ diff --git a/src/assets/fonts/roboto-bold.woff2 b/src/assets/fonts/roboto-bold.woff2 new file mode 100644 index 0000000..b102004 Binary files /dev/null and b/src/assets/fonts/roboto-bold.woff2 differ diff --git a/src/assets/fonts/roboto-medium.ttf b/src/assets/fonts/roboto-medium.ttf new file mode 100644 index 0000000..ac0f908 Binary files /dev/null and b/src/assets/fonts/roboto-medium.ttf differ diff --git a/src/assets/fonts/roboto-medium.woff2 b/src/assets/fonts/roboto-medium.woff2 new file mode 100644 index 0000000..8b1aebb Binary files /dev/null and b/src/assets/fonts/roboto-medium.woff2 differ diff --git a/src/assets/fonts/roboto-regular.ttf b/src/assets/fonts/roboto-regular.ttf new file mode 100644 index 0000000..ddf4bfa Binary files /dev/null and b/src/assets/fonts/roboto-regular.ttf differ diff --git a/src/assets/fonts/roboto-regular.woff2 b/src/assets/fonts/roboto-regular.woff2 new file mode 100644 index 0000000..0aa90fc Binary files /dev/null and b/src/assets/fonts/roboto-regular.woff2 differ diff --git a/src/assets/images/dollar-icon.svg b/src/assets/images/dollar-icon.svg new file mode 100644 index 0000000..c20b593 --- /dev/null +++ b/src/assets/images/dollar-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/favicon.ico b/src/assets/images/favicon.ico new file mode 100644 index 0000000..f77999d Binary files /dev/null and b/src/assets/images/favicon.ico differ diff --git a/src/assets/images/ic_category_foodndrink.png.png b/src/assets/images/ic_category_foodndrink.png.png new file mode 100644 index 0000000..8d61471 Binary files /dev/null and b/src/assets/images/ic_category_foodndrink.png.png differ diff --git a/src/assets/images/ic_category_other_income.png.png b/src/assets/images/ic_category_other_income.png.png new file mode 100644 index 0000000..24d0828 Binary files /dev/null and b/src/assets/images/ic_category_other_income.png.png differ diff --git a/src/assets/images/ic_category_transport.png.png b/src/assets/images/ic_category_transport.png.png new file mode 100644 index 0000000..a7eaf5b Binary files /dev/null and b/src/assets/images/ic_category_transport.png.png differ diff --git a/src/assets/images/icon-search.svg b/src/assets/images/icon-search.svg new file mode 100644 index 0000000..fb1e68a --- /dev/null +++ b/src/assets/images/icon-search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/icon.png b/src/assets/images/icon.png new file mode 100644 index 0000000..519e341 Binary files /dev/null and b/src/assets/images/icon.png differ diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg new file mode 100644 index 0000000..d3ec790 --- /dev/null +++ b/src/assets/images/logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/question-icon.svg b/src/assets/images/question-icon.svg new file mode 100644 index 0000000..30eca57 --- /dev/null +++ b/src/assets/images/question-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/pages/index.html b/src/pages/index.html new file mode 100644 index 0000000..810069e --- /dev/null +++ b/src/pages/index.html @@ -0,0 +1,289 @@ + + + + + + + + Money Lover Web + + + + +
+ +
+

Add a wallet first!

+
+ +
+
+
+
+

Wallet name

+ +
+
+
+
+

Currency

+
+ Dollar icon +

United States Dollar

+
+
+
+
+

Initial Balance

+ +
+
+
+ +
+
+
+
+ + + +
+ +
+

Add budget

+
+ +
+
+
+
+
+

Date

+
+ +
+
+
+
+
+
+

Amount

+ +
+
+
+
+

Note

+ +
+
+ + +
+
+
+
+
+ + + +
+ +
+

Add transaction

+ +
+ +
+
+ +
+
+
+

Date

+
+ + +
+
+
+
+
+

Category

+
+ Question icon + +
+
+
+
+
+
+

Amount

+ +
+
+
+
+

Note

+ +
+
+ + +
+
+
+
+
+ + + +
+
+
+
+
Select category
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ Wallet Icon +
+
+

User

+
+

Log Out

+
+

+$ 0.00

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+ +
+
+ +
+
+

Inflow

+

+$ 0.00

+
+
+

Outflow

+

$ 0.00

+
+
+

+$ 0.00

+
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+ + + diff --git a/src/pages/login.html b/src/pages/login.html new file mode 100644 index 0000000..a914c9d --- /dev/null +++ b/src/pages/login.html @@ -0,0 +1,49 @@ + + + + + + + + Login - Money Lover + + +
+
+
+ Logo web + +
+
+

Log In

+

Using Money Lover account

+ + + + +
+
+ +
+
+
+ + + diff --git a/src/pages/register.html b/src/pages/register.html new file mode 100644 index 0000000..c608c00 --- /dev/null +++ b/src/pages/register.html @@ -0,0 +1,62 @@ + + + + + + + + Register - Money Lover + + +
+
+
+ Logo web + +
+
+

Register

+

Using Money Lover account

+
+ +
+
+ +
+
+ +
+ + + +
+
+ +
+
+
+ + + diff --git a/src/styles/_main.scss b/src/styles/_main.scss new file mode 100644 index 0000000..8e11aa0 --- /dev/null +++ b/src/styles/_main.scss @@ -0,0 +1,21 @@ +// Abstracts +@import './abstracts/mixin'; +@import './abstracts/variables'; + +// Bases +@import './bases/placeholder'; +@import './bases/reset'; +@import './bases/typography'; + +// Components +@import './components/dialog'; +@import './components/icons'; +@import './components/loader'; +@import './components/toast-form'; + +// Layouts +@import './layouts/header'; + +// Pages +@import './pages/login-register'; +@import './pages/index'; diff --git a/src/styles/abstracts/_mixin.scss b/src/styles/abstracts/_mixin.scss new file mode 100644 index 0000000..a1fc14b --- /dev/null +++ b/src/styles/abstracts/_mixin.scss @@ -0,0 +1,27 @@ +@mixin flex-layout( + $justify: null, + $align: null, + $direction: null, + $gap: null, + $wrap: null +) { + @if $justify != null { + justify-content: $justify; + } + + @if $align != null { + align-items: $align; + } + + @if $direction != null { + flex-direction: $direction; + } + + @if $gap != null { + gap: $gap; + } + + @if $wrap != null { + flex-wrap: $wrap; + } +} diff --git a/src/styles/abstracts/_variables.scss b/src/styles/abstracts/_variables.scss new file mode 100644 index 0000000..322974e --- /dev/null +++ b/src/styles/abstracts/_variables.scss @@ -0,0 +1,36 @@ +$primary-font: 'Roboto'; + +// Color +$hover-light-primary-color: #cdecd3; +$light-primary-color: #00bc2a; +$primary-color: #2db84c; +$dark-primary-color: #00710f; +$primary-text-color: #000; +$secondary-text-color: #0000008a; +$secondary-light-text-color: #00000042; +$amount-outcome-color: #e51c23; +$amount-income-color: #039be5; +$background-input-color: #f5f5f5; +$dark-error-color: #ce1414; +$light-error-color: #ffc3c3; +$light-gray: #f4f4f4; +$gray: #dddddd; +$dark-gray: #00000042; +$dark-x-gray: #0000008a; +$white: #ffffff; +$black: #000000; + +// Font size +$fs-2x-sm: 11px; +$fs-x-sm: 12px; +$fs-sm: 14px; +$fs-md: 16px; +$fs-lg: 17px; +$fs-x-lg: 20px; +$fs-2x-lg: 32px; + +// Z-index +$zindex-lv-1: 1; +$zindex-lv-2: 2; +$zindex-lv-3: 3; +$zindex-lv-4: 4; diff --git a/src/styles/bases/_placeholder.scss b/src/styles/bases/_placeholder.scss new file mode 100644 index 0000000..3bd88ef --- /dev/null +++ b/src/styles/bases/_placeholder.scss @@ -0,0 +1,59 @@ +%margin-inline-auto { + margin-inline: auto; +} + +%rounded-x-lg { + border-radius: 50px; +} + +%rounded-lg { + border-radius: 10px; +} + +%rounded { + border-radius: 8px; +} + +%rounded-sm { + border-radius: 4px; +} + +%d-flex { + display: flex; +} + +%d-absolute { + position: absolute; +} + +%base-btn { + border: none; + background: $light-primary-color; + color: $white; + text-transform: uppercase; +} + +%active { + opacity: 1; + pointer-events: auto; +} + +%input-field { + @extend %rounded; + + padding: 6px 16px 13.5px 16px; + border: 1px solid $gray; +} + +%base-layout-item { + @extend %d-flex; + @include flex-layout($justify: space-between); + + padding: 8 0px; +} + +%error-text { + align-self: flex-start; + padding-left: 5px; + color: $dark-error-color; +} diff --git a/src/styles/bases/_reset.scss b/src/styles/bases/_reset.scss new file mode 100644 index 0000000..8604211 --- /dev/null +++ b/src/styles/bases/_reset.scss @@ -0,0 +1,142 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} + +body { + line-height: 1; +} + +ol, +ul { + list-style: none; +} + +blockquote, +q { + quotes: none; +} + +blockquote { + &:before, + &:after { + content: ''; + content: none; + } +} + +q { + &:before, + &:after { + content: ''; + content: none; + } +} + +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/src/styles/bases/_typography.scss b/src/styles/bases/_typography.scss new file mode 100644 index 0000000..2c464d6 --- /dev/null +++ b/src/styles/bases/_typography.scss @@ -0,0 +1,33 @@ +$font-path: '../assets/fonts'; + +@font-face { + font-family: 'Roboto'; + font-weight: 400; + src: url('#{$font-path}/roboto-regular.woff2') format('woff2'), + url('#{$font-path}/roboto-regular.ttf') format('truetype'); + + font-display: swap; +} + +@font-face { + font-family: 'Roboto'; + font-weight: 500; + src: url('#{$font-path}/roboto-medium.woff2') format('woff2'), + url('#{$font-path}/roboto-medium.ttf') format('truetype'); + + font-display: swap; +} + +@font-face { + font-family: 'Roboto'; + font-weight: 700; + src: url('#{$font-path}/roboto-bold.woff2') format('woff2'), + url('#{$font-path}/roboto-bold.ttf') format('truetype'); + + font-display: swap; +} + +* { + font-family: $primary-font, sans-serif; + font-size: $fs-sm; +} diff --git a/src/styles/components/_dialog.scss b/src/styles/components/_dialog.scss new file mode 100644 index 0000000..fa741f0 --- /dev/null +++ b/src/styles/components/_dialog.scss @@ -0,0 +1,28 @@ +.dialog { + @extend %rounded-sm; + + border: none; + background-color: $white; + padding: none; + transition: all 0.3s ease; + + &__title { + font-size: $fs-x-lg; + font-weight: 500; + line-height: 20px; + } + + &::backdrop { + background-color: rgba($color: #000000, $alpha: 0.2); + } +} + +// Login page +.login-page, +.register-page { + .dialog { + @extend %rounded; + + padding: 0px; + } +} diff --git a/src/styles/components/_icons.scss b/src/styles/components/_icons.scss new file mode 100644 index 0000000..fe28d17 --- /dev/null +++ b/src/styles/components/_icons.scss @@ -0,0 +1,61 @@ +.mark { + position: relative; + display: inline-block; + vertical-align: top; + width: 40px; + height: 40px; + border: 2px solid #c4cbd2; + border-radius: 100px; + + &::before, + &::after { + content: ''; + display: block; + position: absolute; + } + + &.success:before { + top: 16px; + left: 15px; + margin: -5px 0 0 -6px; + height: 10px; + width: 20px; + border: solid #39ca74; + border-width: 0 0 3px 3px; + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); + } + + &.error { + &:before { + top: 6px; + left: 13px; + height: 10px; + width: 10px; + border: solid #c0392b; + border-width: 0 0 4px 4px; + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); + } + + &:after { + top: 21px; + left: 13px; + height: 10px; + width: 10px; + border: solid #c0392b; + border-width: 0 0 4px 4px; + -webkit-transform: rotate(135deg); + -moz-transform: rotate(135deg); + -ms-transform: rotate(135deg); + -o-transform: rotate(135deg); + transform: rotate(135deg); + } + } +} diff --git a/src/styles/components/_loader.scss b/src/styles/components/_loader.scss new file mode 100644 index 0000000..420e52d --- /dev/null +++ b/src/styles/components/_loader.scss @@ -0,0 +1,39 @@ +.loader { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: #00000066; + z-index: $zindex-lv-1; + transition: + opacity 0.75s, + visibility 0.75s; + + &::after { + content: ''; + width: 75px; + height: 75px; + border: 10px solid $gray; + border-top-color: $primary-color; + border-radius: 50%; + animation: loading 0.75s ease infinite; + } + + &.hidden { + opacity: 0; + visibility: hidden; + } +} + +@keyframes loading { + from { + transform: rotate(0turn); + } + to { + transform: rotate(1turn); + } +} diff --git a/src/styles/components/_toast-form.scss b/src/styles/components/_toast-form.scss new file mode 100644 index 0000000..60ff0dd --- /dev/null +++ b/src/styles/components/_toast-form.scss @@ -0,0 +1,32 @@ +.toast { + @extend %d-flex; + @include flex-layout($direction: column, $align: center, $gap: 30px); + + padding: 40px 50px; + + &__title { + font-size: $fs-2x-lg; + } + + &__message { + font-size: $fs-lg; + text-align: center; + } + + &__redirect-btn { + color: $white; + font-size: $fs-md; + border: none; + border-radius: 10px; + padding: 15px 30px; + cursor: pointer; + } +} + +.success .toast__redirect-btn { + background-color: $light-primary-color; +} + +.error .toast__redirect-btn { + background-color: $dark-error-color; +} diff --git a/src/styles/layouts/_header.scss b/src/styles/layouts/_header.scss new file mode 100644 index 0000000..676a7a7 --- /dev/null +++ b/src/styles/layouts/_header.scss @@ -0,0 +1,36 @@ +.home-page { + .header { + position: fixed; + top: 0; + left: 0; + right: 0; + background-color: $white; + + &__content { + @extend %d-flex; + @include flex-layout($justify: space-between, $align: center); + + padding: 12px 8px; + } + + &__left-content { + @extend %d-flex; + @include flex-layout($align: center, $gap: 12px); + } + + &__add-btn { + @extend %base-btn, %rounded-sm; + + height: 32px; + padding-inline: 12px; + font-weight: 500; + line-height: 16px; + transition: 0.2s; + cursor: pointer; + + &:hover { + background: $dark-primary-color; + } + } + } +} diff --git a/src/styles/pages/_index.scss b/src/styles/pages/_index.scss new file mode 100644 index 0000000..0ea8664 --- /dev/null +++ b/src/styles/pages/_index.scss @@ -0,0 +1,702 @@ +.home-page { + .background { + height: 100vh; + background: $gray; + overflow: auto; + } + + .wrapper { + max-width: 1920px; + margin-inline: auto; + } + + .main { + padding-top: 96px; + } + + .wallet { + @extend %d-flex; + @include flex-layout($align: center, $gap: 8px); + + min-width: 170px; + + &__icon { + width: 40px; + height: 41px; + } + + &__info { + position: relative; + } + + &__dialog { + @extend %rounded-sm; + + padding: 10px; + position: absolute; + background-color: $white; + border: 1px solid $black; + top: 17px; + left: 10px; + opacity: 0; + visibility: none; + transition: 0.3s; + + &:hover { + visibility: visible; + opacity: 1; + } + } + + &__name { + font-size: $fs-x-sm; + line-height: 21px; + + &:hover + .wallet__dialog { + visibility: visible; + opacity: 1; + } + } + + &__price { + line-height: 18px; + font-weight: 700; + } + } + + .app { + border-radius: 4px; + background: $white; + box-shadow: 0px 3px 24px 0px rgba(0, 0, 0, 0.12); + margin-inline: auto; + width: 624px; + margin-bottom: 20px; + + &__tabs { + padding-top: 20px; + text-align: center; + border-bottom: 1px solid $gray; + position: relative; + } + + &__tab-item { + font-weight: 500; + color: $dark-x-gray; + background: none; + border: none; + padding: 15px 23.62px; + cursor: pointer; + + &.active { + color: $primary-color; + } + } + + &__content-item { + display: none; + animation: fade 0.5s ease; + + &.active { + display: block; + } + } + + &__line { + position: absolute; + top: 66px; + left: 152px; + width: 116px; + height: 2px; + background-color: $primary-color; + border-radius: 10px; + transition: all 0.3s ease-in-out; + } + } + + .summary { + @extend %d-flex; + @include flex-layout($direction: column); + + padding: 10px 16px 40px; + text-align: right; + + &__line { + width: 150px; + height: 1px; + background-color: $gray; + align-self: flex-end; + } + + &__total { + margin-top: 5px; + font-size: $fs-md; + line-height: 16px; + } + } + + .inflow { + @extend %base-layout-item; + + &__text { + line-height: 16px; + + &--income { + font-size: $fs-md; + color: $amount-income-color; + } + } + } + + .outflow { + @extend %base-layout-item; + + &__text { + line-height: 16px; + + &--outcome { + font-size: $fs-md; + color: $amount-outcome-color; + } + } + } + + .transaction { + background: $light-gray; + + &__line { + width: 100%; + height: 1px; + background-color: $gray; + } + + &__list { + @extend %d-flex; + @include flex-layout( + $justify: space-between, + $gap: 32px, + $direction: column + ); + } + + &__item { + background-color: $white; + } + + &__category { + @extend %d-flex; + @include flex-layout($justify: space-between, $align: center); + + padding: 16px; + + &-infor { + @extend %d-flex; + @include flex-layout($align: center, $gap: 9px); + } + + &-icon-container { + width: 40px; + height: 40px; + } + + &-name { + font-weight: 500; + line-height: 20px; + } + + &-total { + font-size: $fs-lg; + line-height: 15px; + } + } + + &__total { + font-size: $fs-x-sm; + color: $dark-x-gray; + line-height: 16px; + } + + &__time { + @extend %d-flex; + @include flex-layout($justify: space-between, $align: center); + + padding: 16px; + cursor: pointer; + + &:hover { + background-color: $hover-light-primary-color; + } + } + + &__details { + @extend %d-flex; + @include flex-layout($justify: space-between, $align: center, $gap: 12px); + } + + &__day { + font-size: $fs-2x-lg; + line-height: 16px; + font-weight: 300; + } + + &__date-time { + font-size: $fs-2x-sm; + line-height: 15px; + text-transform: capitalize; + } + + &__note { + @extend .transaction__date-time; + + color: $dark-gray; + } + + &__outcome { + color: $amount-outcome-color; + } + + &__income { + color: $amount-income-color; + } + } + + .dialog { + // Add wallet dialog + &__add-wallet { + .dialog { + &__body { + padding: 17px 24px; + } + + &__header { + border-bottom: 1px solid $gray; + } + + &__title { + padding: 20px 24px 24px 24px; + } + } + + .form { + &__save-btn { + margin-top: 31px; + align-self: flex-end; + } + + &__currency-balance { + @extend %d-flex; + @include flex-layout($justify: space-between, $gap: 20px); + + margin-top: 16px; + } + + &__wrap-text-icon { + @extend %d-flex; + @include flex-layout($gap: 16px, $align: center); + + margin-top: 6px; + width: 230px; + } + + &__text-currency { + font-size: $fs-md; + line-height: 24px; + } + + &__input-field { + height: fit-content; + } + } + } + + // Add budget dialog + &__add-budget { + .dialog { + &__body { + padding: 24px 40px 0; + } + + &__title { + padding: 20px 40px; + } + } + + .form { + &__date-amount-input { + @extend %d-flex; + @include flex-layout($gap: 32px); + + & .form__input-container { + width: 100%; + } + } + + &__note-input { + @extend %input-field; + + width: 768px; + margin-top: 24px; + } + + &__input-text { + width: 100%; + } + + &__cancel-btn { + width: 96px; + height: 36px; + } + + &__save-btn { + width: 96px; + height: 36px; + } + } + } + + // Add transaction dialog + &__add-transaction { + .dialog { + &__header { + @extend %d-flex; + @include flex-layout($justify: space-between, $align: center); + + padding: 20px 40px; + } + + &__body { + padding: 24px 40px 0; + } + } + + .form { + &__date-category-amount-input { + @extend %d-flex; + @include flex-layout($justify: space-between, $gap: 24px); + } + + &__input-field:first-child { + width: 255px; + } + + &__input-field:nth-child(2), + &__input-field:nth-child(3) { + width: 240px; + } + + &__note-input { + @extend %input-field; + + margin-top: 24px; + } + + &__save-btn { + width: 96px; + height: 36px; + } + } + } + + // Select category dialog + &__select-category { + .dialog { + &__header { + padding-top: 15px; + position: relative; + border-bottom: 1px solid $gray; + } + + &__title-container { + @extend %d-flex; + @include flex-layout($align: center, $gap: 28px); + + padding-left: 24px; + } + + &__title { + font-weight: 400; + } + } + + .form { + padding: 10px 144px; + + &__search-container { + @extend %d-flex, %rounded-x-lg; + @include flex-layout( + $justify: flex-end, + $gap: 16px, + $direction: row-reverse, + $align: center + ); + + padding-inline: 16px; + width: 208px; + height: 51px; + background-color: $light-gray; + } + + &__category-input-field { + border: none; + background-color: transparent; + + &:focus { + outline: none; + } + } + + &__search-btn { + cursor: pointer; + border: none; + background-color: transparent; + } + } + } + } + + // Common property + .form { + @extend %d-flex; + @include flex-layout($direction: column); + + &__input-field { + @extend %rounded; + + padding: 6px 16px 12px; + border: 1px solid $gray; + } + + &__label { + color: $dark-x-gray; + font-size: $fs-x-sm; + line-height: 18px; + } + + &__input-text { + margin-top: 7px; + font-size: $fs-lg; + width: 100%; + border: none; + background-color: transparent; + + &:focus { + outline: none; + } + + &::placeholder { + color: $gray; + } + } + + &__input-balance { + font-size: $fs-lg; + line-height: 20px; + height: 28px; + border: none; + width: 100%; + background-color: transparent; + + &:focus { + outline: none; + } + } + + &__save-btn { + @extend %rounded-sm; + + border: none; + background-color: $gray; + line-height: 16.1px; + font-weight: 500; + padding: 10px 20px; + color: $dark-gray; + cursor: pointer; + + &.active { + background-color: $primary-color; + color: $white; + } + } + + &__cancel-btn { + @extend .form__save-btn; + + color: $primary-color !important; + margin-right: 16px; + transition: 0.3s; + + &:hover { + background-color: $hover-light-primary-color; + } + } + + &__delete-btn { + @extend .form__save-btn; + + color: $dark-error-color !important; + transition: 0.3s; + + &:hover { + background-color: $light-error-color; + } + } + + &__action { + align-self: flex-end; + margin-top: 64px; + padding: 14px 0; + } + } + + .date-input-container { + position: relative; + float: left; + width: 100%; + } + + .input-date { + height: 30px; + width: 100%; + border: none; + font-size: $fs-lg; + background-color: transparent; + + &:focus { + outline: none; + } + + &::-webkit-calendar-picker-indicator { + background: transparent; + cursor: pointer; + } + } + + .icon-btn { + position: absolute; + top: 10px; + right: 5px; + background-color: transparent; + border-top: 3px solid $dark-gray; + border-right: 3px solid $dark-gray; + border-bottom: none; + border-left: none; + height: 7px; + width: 7px; + rotate: 45deg; + pointer-events: none; + } + + .category-input-container { + @extend %d-flex; + @include flex-layout($align: center, $gap: 8px); + + position: relative; + margin-top: 4px; + + & .category-icon { + height: 24px; + width: 24px; + } + } + + .category-name { + font-size: $fs-lg; + line-height: 25.5px; + color: $black; + border: none; + caret-color: transparent; + background-color: transparent; + cursor: pointer; + + &:focus { + outline: none; + } + } + + .icon-category { + width: 40px; + height: 40px; + } + + .list-category { + @extend %d-flex; + @include flex-layout($direction: column); + + padding-top: 5px; + height: 451px; + overflow: auto; + } + + .category-item { + @extend %d-flex; + @include flex-layout($align: center, $gap: 16px); + + margin-inline: 68px; + padding: 8px 0; + border-bottom: 1px solid $gray; + transition: 0.3s; + cursor: pointer; + + &:hover, + &.selected { + background-color: $hover-light-primary-color; + } + } + + .logout-text { + font-size: $fs-x-sm; + cursor: pointer; + + &:hover { + color: $primary-color; + } + } + + .error-input { + background-color: $light-error-color; + border-color: $dark-error-color; + + & .form__input-text::placeholder { + color: $white; + } + } + + .error-text { + @extend %error-text; + } + + .form__input-container { + @extend %d-flex; + @include flex-layout($direction: column, $gap: 7px); + } +} + +.close-icon { + @extend .error, .mark; + + border: none; + cursor: pointer; + + &::after, + &::before { + border-color: $black; + border-width: 0 0 2px 2px; + } +} + +.hide { + opacity: 0; + pointer-events: none; +} + +@keyframes fade { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +#categoryForm { + z-index: $zindex-lv-4; +} diff --git a/src/styles/pages/_login-register.scss b/src/styles/pages/_login-register.scss new file mode 100644 index 0000000..3171f3d --- /dev/null +++ b/src/styles/pages/_login-register.scss @@ -0,0 +1,100 @@ +.login-page, +.register-page { + .background { + height: 100vh; + background: linear-gradient($dark-primary-color 314px, #ebebeb -100%); + } + + .wrapper { + @extend %margin-inline-auto; + @extend %d-absolute; + + top: 0; + left: 0; + right: 0; + text-align: center; + } + + .logo-web { + padding-top: 54px; + } + + .form { + @extend %margin-inline-auto; + + margin-top: 34px; + padding-top: 34px; + padding-bottom: 40px; + background-color: $white; + width: 670px; + border-radius: 20px; + + &__container { + @extend %margin-inline-auto; + + display: flex; + flex-direction: column; + gap: 19px; + width: 280px; + } + + &__title { + color: $primary-text-color; + font-size: $fs-2x-lg; + font-weight: 700; + line-height: 48px; + } + + &__error-message { + font-size: $fs-md; + background-color: $light-error-color; + color: $dark-error-color; + padding: 15px 15px; + border-radius: 10px; + line-height: 22px; + list-style: inside; + } + + &__description { + margin-top: 15px; + color: $secondary-text-color; + font-size: $fs-md; + line-height: 24px; + } + + &__input { + @extend %rounded-lg; + + font-size: $fs-md; + height: 52px; + border: 2px solid $background-input-color; + background-color: $background-input-color; + padding-inline: 14px; + + &-container { + @extend %d-flex; + @include flex-layout($direction: column, $gap: 7px); + } + } + + &__submit-btn { + @extend %rounded-lg, %base-btn; + + height: 36px; + margin-top: 30px; + } + + &__link { + color: $primary-color; + } + } + + .error-input { + border: 2px solid $dark-error-color; + background-color: $light-error-color; + } + + .error-text { + @extend %error-text; + } +} diff --git a/src/ts/app.ts b/src/ts/app.ts new file mode 100644 index 0000000..aa120c1 --- /dev/null +++ b/src/ts/app.ts @@ -0,0 +1,17 @@ +import Controller from './controllers/index'; +import Service from './services/index'; +import View from './views/index'; + +export default class App { + controller: Controller; + + constructor() { + this.controller = new Controller(new Service(), new View()); + } + + start() { + this.controller.registerController.init(); + this.controller.loginController.init(); + this.controller.homeController.init(); + } +} diff --git a/src/ts/constants/config.ts b/src/ts/constants/config.ts new file mode 100644 index 0000000..dce8da0 --- /dev/null +++ b/src/ts/constants/config.ts @@ -0,0 +1,66 @@ +export const DATABASE_URL = + 'https://javascript-training-81f7a-default-rtdb.asia-southeast1.firebasedatabase.app'; +export const TIME_OUT_SEC = 3; + +export const BTN_CONTENT = { + GOT_IT: 'Got it!', + OK: 'Ok', +}; + +export const LOCAL_STORAGE = { + ACCESS_TOKEN: 'accessToken', +}; + +export const TypeToast = { + success: 'success', + error: 'error', +}; + +export const MarkIcon = { + success: 'success', + error: 'error', +}; + +export const REGEX = { + PASSWORD: + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, + EMAIL: + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, +}; + +export const URL = { + LOGIN: 'login', + REGISTER: 'register', + HOME: '', +}; + +export const DEFAULT_CATEGORY = { + INCOME: 'Income', +}; + +export const REMOVE_CATEGORY = ['Income']; + +export const DAY = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', +]; + +export const MONTH = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; diff --git a/src/ts/constants/defaultVariable.ts b/src/ts/constants/defaultVariable.ts new file mode 100644 index 0000000..a417742 --- /dev/null +++ b/src/ts/constants/defaultVariable.ts @@ -0,0 +1 @@ +export const FIRST_ADD_WALLET_NOTE: string = 'Init Wallet'; diff --git a/src/ts/constants/messages.ts b/src/ts/constants/messages.ts new file mode 100644 index 0000000..38b5b28 --- /dev/null +++ b/src/ts/constants/messages.ts @@ -0,0 +1,23 @@ +export const VALIDATE_FORM = { + INVALID_EMAIL_FORMAT: `The email is not correct!`, + PASSWORD_NOT_MATCH: 'Password not match!', + PASSWORD_NOT_STRONG: + 'Password must at least one uppercase, one lowercase letter, one number and one special character!', + ERROR_CREDENTIAL: { + title: 'Error Credential', + message: 'Email or password not match! Please try again!', + }, + REQUIRED_MESSAGE: (field: string) => `The ${field} is required!`, +}; + +export const TOAST = { + ERROR_MESSAGE_DEFAULT: ['Something went wrong!'], + TIME_OUT_ERROR: 'Connection time out! Please try again!', + DEFAULT_TITLE_ERROR_TOAST: 'Error', + USER_EXIST_ERROR: 'User is exists! Please try another email!', + ADD_WALLET_SUCCESS: 'Add wallet success!', + DEFAULT_MESSAGE: 'Press OK to continue!', + ADD_TRANSACTION_SUCCESS: 'Add success!', + UPDATE_TRANSACTION_SUCCESS: 'Update success!', + REGISTER_SUCCESS: 'Register Success', +}; diff --git a/src/ts/controllers/homeController.ts b/src/ts/controllers/homeController.ts new file mode 100644 index 0000000..54b1ddf --- /dev/null +++ b/src/ts/controllers/homeController.ts @@ -0,0 +1,65 @@ +import HomeView from 'views/home/homeView'; +import Service from 'services'; +import Wallet from 'models/wallet'; +import Transaction from 'models/transaction'; +import Category from 'models/category'; +import { IHomeFunc, Nullable } from 'global/types'; + +export default class HomeController { + constructor( + public service: Service, + public homeView: Nullable, + ) { + this.service = service; + this.homeView = homeView; + } + + handlerGetInfoUserLogin() { + return this.service.userService.getInfoUserLogin(); + } + + handlerGetWalletByIdUser(idUser: string): Promise { + return this.service.walletService.getWalletByIdUser(idUser); + } + + handlerSaveWallet(wallet: Wallet): Promise { + return this.service.walletService.saveWallet(wallet); + } + + handlerSaveTransaction(transaction: Transaction): Promise { + return this.service.transactionService.saveTransaction(transaction); + } + + handlerGetAllCategory(): Promise { + return this.service.categoryService.getAllCategory(); + } + + handlerGetAllTransactions(idUser: string): Promise { + return this.service.transactionService.getListTransactionByIdUser(idUser); + } + + handlerDeleteTransaction(idTransaction: string): Promise { + return this.service.transactionService.deleteTransaction(idTransaction); + } + + init() { + if (this.homeView) { + const func: IHomeFunc = { + getInfoUserLogin: this.handlerGetInfoUserLogin.bind(this), + getWalletByIdUser: this.handlerGetWalletByIdUser.bind(this), + getAllCategory: this.handlerGetAllCategory.bind(this), + getAllTransactions: this.handlerGetAllTransactions.bind(this), + saveWallet: this.handlerSaveWallet.bind(this), + saveTransaction: this.handlerSaveTransaction.bind(this), + deleteTransaction: this.handlerDeleteTransaction.bind(this), + }; + + this.homeView.initFunction(func); + + this.homeView.loadPage(); + + // Subscribe listener data update + this.homeView.subscribeListenerData(); + } + } +} diff --git a/src/ts/controllers/index.ts b/src/ts/controllers/index.ts new file mode 100644 index 0000000..ce7bc54 --- /dev/null +++ b/src/ts/controllers/index.ts @@ -0,0 +1,25 @@ +import Service from 'services'; +import RegisterController from './registerController'; +import View from 'views'; +import LoginController from './loginController'; +import HomeController from './homeController'; + +export default class Controller { + public registerController: RegisterController; + + public loginController: LoginController; + + public homeController: HomeController; + + constructor( + public service: Service, + public view: View, + ) { + this.registerController = new RegisterController( + service, + view.registerView, + ); + this.loginController = new LoginController(service, view.loginView); + this.homeController = new HomeController(service, view.homeView); + } +} diff --git a/src/ts/controllers/loginController.ts b/src/ts/controllers/loginController.ts new file mode 100644 index 0000000..a6c79f6 --- /dev/null +++ b/src/ts/controllers/loginController.ts @@ -0,0 +1,29 @@ +import { Nullable } from 'global/types'; +import User from 'models/user'; +import Service from 'services'; +import LoginView from 'views/loginView'; + +export default class LoginController { + constructor( + public service: Service, + public loginView: Nullable, + ) { + this.service = service; + this.loginView = loginView; + } + + handlerLoginUser(email: string, password: string): Promise { + return this.service.userService.loginUser(email, password); + } + + handlerGetInfoUserLogin(): Promise { + return this.service.userService.getInfoUserLogin(); + } + + init() { + if (this.loginView) { + this.loginView.loadPage(this.handlerGetInfoUserLogin.bind(this)); + this.loginView.addHandlerForm(this.handlerLoginUser.bind(this)); + } + } +} diff --git a/src/ts/controllers/registerController.ts b/src/ts/controllers/registerController.ts new file mode 100644 index 0000000..8c94fa7 --- /dev/null +++ b/src/ts/controllers/registerController.ts @@ -0,0 +1,37 @@ +import { Nullable } from 'global/types'; +import User from 'models/user'; +import Service from 'services'; +import RegisterView from 'views/registerView'; + +export default class RegisterController { + constructor( + public service: Service, + public registerView: Nullable, + ) { + this.service = service; + this.registerView = registerView; + } + + handlerCheckUserValid(email: string): Promise { + return this.service.userService.isValidUser(email); + } + + handlerSaveUser(user: User): Promise { + return this.service.userService.saveUser(user); + } + + handlerGetInfoUserLogin(): Promise { + return this.service.userService.getInfoUserLogin(); + } + + init() { + if (this.registerView) { + this.registerView.loadPage(this.handlerGetInfoUserLogin.bind(this)); + this.registerView.addHandlerForm( + this.handlerCheckUserValid.bind(this), + this.handlerSaveUser.bind(this), + ); + this.registerView.addHandlerInputFormChange(); + } + } +} diff --git a/src/ts/global/types.ts b/src/ts/global/types.ts new file mode 100644 index 0000000..e4ef3c3 --- /dev/null +++ b/src/ts/global/types.ts @@ -0,0 +1,98 @@ +import Category from 'models/category'; +import Transaction from 'models/transaction'; +import User from 'models/user'; +import Wallet from 'models/wallet'; + +export interface IDataObject { + id: string; + data: T; +} + +export class DataObject { + public id: string; + + public data: T; + + constructor(dataObject: IDataObject) { + this.id = dataObject?.id ?? null; + this.data = dataObject.data; + } +} + +export interface IError { + title: string; + message: string; +} + +export type TError = string | IError; + +export class CustomError extends Error { + constructor( + public title: string, + message?: string, + ) { + super(message); + } +} + +export interface Data { + wallet?: Wallet; + listTransactions?: Transaction[]; + listCategories?: Category[]; + user?: User; +} + +export interface ItemTransaction { + id: string; + day: string; + fullDateString: string; + note: string; + amount: number; +} + +export type Nullable = T | null; +export type PromiseVoid = () => Promise; +export type VoidFunc = () => void; +export type PromiseOrNull = () => Promise; + +export interface IHomeFunc { + getInfoUserLogin?: PromiseOrNull; + getWalletByIdUser?: (idUser: string) => Promise; + getAllCategory?: PromiseOrNull; + getAllTransactions?: (idUser: string) => Promise; + saveWallet?: (wallet: Wallet) => Promise; + saveTransaction?: (transaction: Transaction) => Promise; + deleteTransaction?: (idTransaction: string) => Promise; +} + +export interface IBudgetViewFunc { + showErrorToast: (error: TError) => void; + showSuccessToast: (title: string, message: string) => void; + toggleLoaderSpinner: VoidFunc; + saveTransaction: Nullable<(transaction: Transaction) => Promise>; + loadTransactionData: PromiseVoid; + updateAmountWallet: PromiseVoid; + loadData: PromiseVoid; +} + +export interface ITransactionViewFunc { + toggleLoaderSpinner: VoidFunc; + deleteTransaction: (idTransaction: string) => Promise; + loadTransactionData: PromiseVoid; + updateAmountWallet: PromiseVoid; + loadData: PromiseVoid; + showSuccessToast: (title: string, message: string) => void; + showErrorToast: (error: TError) => void; + saveTransaction: (transaction: Transaction) => Promise; +} + +export interface IWalletViewFunc { + toggleLoaderSpinner: () => void; + saveWallet: ((wallet: Wallet) => Promise) | null; + saveTransaction: ((transaction: Transaction) => Promise) | null; + loadTransactionData: () => Promise; + loadData: () => Promise; + loadEvent: () => void; + showSuccessToast: (title: string, message: string) => void; + showErrorToast: (error: TError) => void; +} diff --git a/src/ts/helpers/connect.ts b/src/ts/helpers/connect.ts new file mode 100644 index 0000000..7560fb1 --- /dev/null +++ b/src/ts/helpers/connect.ts @@ -0,0 +1,33 @@ +import { TOAST } from '../constants/messages'; +import { TIME_OUT_SEC } from '../constants/config'; +import FirebaseService from '../services/firebaseService'; + +/** + * A waiting function with s second + * @param {number} s The time will be waiting + * @returns {Promise} A Promise will be only reject after s second + */ +export const timeout = (s: number): Promise => { + return new Promise((_, reject) => { + setTimeout(() => { + FirebaseService.disconnect(); + reject(TOAST.TIME_OUT_ERROR); + }, s * 1000); + }); +}; + +/** + * A function waiting the action need to be perform and throw error after s second. + * @param {Function} action The action need to be perform. + * @returns { Object || Error } Return the any object from Firebase or Error + */ +export const timeOutConnect = async ( + action: Promise, +): Promise => { + const result: T | string = await Promise.race([ + action, + timeout(TIME_OUT_SEC), + ]); + + return result; +}; diff --git a/src/ts/helpers/data.ts b/src/ts/helpers/data.ts new file mode 100644 index 0000000..ed9759f --- /dev/null +++ b/src/ts/helpers/data.ts @@ -0,0 +1,125 @@ +import localStorageService from 'services/localStorageService'; +import { DataObject, IDataObject, ItemTransaction } from '../global/types'; +import { DAY, LOCAL_STORAGE, MONTH } from 'constants/config'; +import Transaction from 'models/transaction'; +import TransactionDetail from 'models/transactionDetail'; +import Category from 'models/category'; + +export const generateId = (): string => { + return new Date().getTime().toString(); +}; + +export const convertDataObjectToModel = (dataObj: DataObject): T => { + const { id } = dataObj; + + return { id, ...dataObj.data } as T; +}; + +export const convertModelToDataObject = (model: T): DataObject => { + const { id, ...data } = model as IDataObject; + + return { id, data } as DataObject; +}; + +/** + * A function create token for user + * @returns {string} Return token string + */ +export const createToken = (): string => { + const lengthToken: number = 36; + const chars: string = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + let token: string = ''; + for (let i: number = 0; i < lengthToken; i += 1) { + token += chars[Math.floor(Math.random() * chars.length)]; + } + return token; +}; + +export const formatNumber = (number: number): string => { + return number.toLocaleString(undefined, { + minimumFractionDigits: 2, + }); +}; + +export const changeDateFormat = (oldFormatDate: string) => { + const tempDate = new Date(oldFormatDate); + + const day = DAY[tempDate.getDay()]; + const date = tempDate.getDate(); + const month = MONTH[tempDate.getMonth()]; + const year = tempDate.getFullYear(); + + return `${day}, ${date}, ${month}, ${year}`; +}; + +export const clearAccessToken = (): void => { + localStorageService.remove(LOCAL_STORAGE.ACCESS_TOKEN); +}; + +export const getAllCategoryNameInTransactions = ( + transactions: Transaction[], +): string[] => { + const categoryName = new Set(); + + transactions.forEach((transaction) => + categoryName.add(transaction.categoryName), + ); + + return Array.from(categoryName) as string[]; +}; + +export const getAllTransactionByCategoryName = ( + categoryName: string, + transactions: Transaction[], +) => { + const results = transactions.filter((transaction) => { + return transaction.categoryName === categoryName; + }); + + return results; +}; + +export const createTransactionDetailObject = ( + category: Category, + transactions: Transaction[], +): TransactionDetail => { + const totalTransaction = transactions.length; + const totalAmount = () => { + let amount = 0; + + transactions.forEach((transaction) => { + amount += transaction.amount; + }); + + return amount; + }; + const listTransaction = (): ItemTransaction[] => { + const results: ItemTransaction[] = transactions.map((transaction) => { + const dateParts = changeDateFormat(transaction.date).split(','); // ['Monday', '14', 'September', '2023'] + const day = dateParts[1]; + const fullDateString = `${dateParts[0]}, ${dateParts[2]} ${dateParts[3]}`; + const tempData: ItemTransaction = { + id: transaction.id, + day, + fullDateString, + note: transaction.note, + amount: transaction.amount, + }; + + return tempData; + }); + + results.sort((a, b) => parseInt(b.id) - parseInt(a.id)); + + return results; + }; + + return new TransactionDetail( + category.name, + category.url, + totalTransaction, + totalAmount(), + listTransaction(), + ); +}; diff --git a/src/ts/helpers/evDataTrigger.ts b/src/ts/helpers/evDataTrigger.ts new file mode 100644 index 0000000..00178f7 --- /dev/null +++ b/src/ts/helpers/evDataTrigger.ts @@ -0,0 +1,46 @@ +import { Data } from 'global/types'; + +type TSignal = { + [key: string]: { + name: string; + handler: (value: Data) => void; + }; +}; + +export default class EventDataTrigger { + private static _instance: EventDataTrigger; + + public signal: TSignal; + + constructor() { + this.signal = {}; + } + + public static get Instance() { + return this._instance || (this._instance = new this()); + } + + onSendSignal(fromClass: string, value: Data) { + Object.keys(this.signal).forEach((key) => { + const item = this.signal[key as keyof TSignal]; + + // Same receiver + if (item.name === fromClass) { + return; + } + + // Send signal + const { handler } = this.signal[key]; + if (handler) { + handler(value); + } + }); + } + + create( + className: string, + handler: ((value: Data) => void) | null = null, + ): void { + if (handler) this.signal[className] = { name: className, handler }; + } +} diff --git a/src/ts/helpers/url.ts b/src/ts/helpers/url.ts new file mode 100644 index 0000000..40e8f06 --- /dev/null +++ b/src/ts/helpers/url.ts @@ -0,0 +1,16 @@ +export const redirectToLoginPage = () => { + window.location.replace('/login'); +}; + +export const getSubdirectoryURL = (): string => { + const url = window.location.href; + const parts = url.split('/'); // Results: ['http:', '', 'example.com', ''] + const subDirectory = parts[3]; // Get subdirectory url only + const index = subDirectory.indexOf('?'); // Remove query behind subDirectory + + if (index !== -1) { + return subDirectory.substring(0, index); + } + + return subDirectory; +}; diff --git a/src/ts/helpers/validatorForm.ts b/src/ts/helpers/validatorForm.ts new file mode 100644 index 0000000..ef158e1 --- /dev/null +++ b/src/ts/helpers/validatorForm.ts @@ -0,0 +1,30 @@ +import { REGEX } from '../constants/config'; +import { VALIDATE_FORM } from '../constants/messages'; + +/** + * Validate password + * @param {string} password Password input + * @returns {boolean} Return true if validate password success, otherwise return false + */ +export const isValidPassword = (password: string): boolean => { + return REGEX.PASSWORD.test(password); +}; + +export const isValidateEmail = (email: string): RegExpMatchArray | null => { + return String(email).toLowerCase().match(REGEX.EMAIL); +}; + +export const compare2Password = ( + password: string, + passwordConfirm: string, +): boolean => { + return password === passwordConfirm; +}; + +export const renderRequiredText = (field: string, element: Element) => { + const markup: string = ` +

${VALIDATE_FORM.REQUIRED_MESSAGE(field)}

+ `; + + element.insertAdjacentHTML('afterend', markup); +}; diff --git a/src/ts/index.ts b/src/ts/index.ts new file mode 100644 index 0000000..851ad8e --- /dev/null +++ b/src/ts/index.ts @@ -0,0 +1,8 @@ +import App from './app'; + +// Sure that scripts called after DOM loaded +document.addEventListener('DOMContentLoaded', () => { + const myApp = new App(); + + myApp.start(); +}); diff --git a/src/ts/models/category.ts b/src/ts/models/category.ts new file mode 100644 index 0000000..c1c10cc --- /dev/null +++ b/src/ts/models/category.ts @@ -0,0 +1,11 @@ +export default class Category { + constructor( + public id: string, + public url: string, + public name: string, + ) { + this.id = id; + this.url = url; + this.name = name; + } +} diff --git a/src/ts/models/transaction.ts b/src/ts/models/transaction.ts new file mode 100644 index 0000000..339b4b8 --- /dev/null +++ b/src/ts/models/transaction.ts @@ -0,0 +1,19 @@ +import { generateId } from 'helpers/data'; + +export default class Transaction { + constructor( + public id: string, + public categoryName: string, + public date: string, + public note: string, + public amount: number, + public idUser: string, + ) { + this.id = id ? id : generateId(); + this.categoryName = categoryName; + this.date = date; + this.note = note; + this.amount = amount; + this.idUser = idUser; + } +} diff --git a/src/ts/models/transactionDetail.ts b/src/ts/models/transactionDetail.ts new file mode 100644 index 0000000..0586936 --- /dev/null +++ b/src/ts/models/transactionDetail.ts @@ -0,0 +1,17 @@ +import { ItemTransaction } from 'global/types'; + +export default class TransactionDetail { + constructor( + public categoryName: string, + public url: string, + public totalTransaction: number, + public totalAmount: number, + public transactions: ItemTransaction[], + ) { + this.categoryName = categoryName; + this.url = url; + this.totalTransaction = totalTransaction; + this.totalAmount = totalAmount; + this.transactions = transactions; + } +} diff --git a/src/ts/models/user.ts b/src/ts/models/user.ts new file mode 100644 index 0000000..e71f324 --- /dev/null +++ b/src/ts/models/user.ts @@ -0,0 +1,15 @@ +import { generateId } from '../helpers/data'; + +export default class User { + constructor( + public id: string, + public email: string, + public password: string, + public accessToken?: string, + ) { + this.id = id ? id : generateId(); + this.email = email; + this.password = password || ''; + this.accessToken = accessToken || ''; + } +} diff --git a/src/ts/models/wallet.ts b/src/ts/models/wallet.ts new file mode 100644 index 0000000..548da74 --- /dev/null +++ b/src/ts/models/wallet.ts @@ -0,0 +1,17 @@ +import { generateId } from '../helpers/data'; + +export default class Wallet { + constructor( + public id: string, + public walletName: string, + public inflow: number, + public outflow: number, + public idUser: string, + ) { + this.id = id ? id : generateId(); + this.walletName = walletName; + this.inflow = inflow; + this.outflow = outflow; + this.idUser = idUser; + } +} diff --git a/src/ts/services/categoryService.ts b/src/ts/services/categoryService.ts new file mode 100644 index 0000000..b471a33 --- /dev/null +++ b/src/ts/services/categoryService.ts @@ -0,0 +1,32 @@ +import CommonService from './commonService'; +import Category from '../models/category'; + +export default class CategoryService extends CommonService { + constructor() { + super(); + + this.defaultPath = 'categories/'; + } + + async getAllCategory() { + const data = await this.getAllDataFromPath(this.defaultPath); + + if (data) { + return data.reverse().map((category): Category => category); + } + + return null; + } + + async getCategoryByName(nameCategory: string) { + const data = await this.getDataFromProp( + 'name', + nameCategory, + this.defaultPath, + ); + + if (data) return data; + + return null; + } +} diff --git a/src/ts/services/commonService.ts b/src/ts/services/commonService.ts new file mode 100644 index 0000000..1c0a36c --- /dev/null +++ b/src/ts/services/commonService.ts @@ -0,0 +1,131 @@ +import { timeOutConnect } from '../helpers/connect'; +import { + convertDataObjectToModel, + convertModelToDataObject, +} from '../helpers/data'; +import { DataObject } from '../global/types'; +import FirebaseService from './firebaseService'; + +export default class CommonService { + public defaultPath: string; + + public firebaseService = FirebaseService; + + constructor(defaultPath?: string) { + this.defaultPath = defaultPath ? defaultPath : '/'; + } + + /** + * Connect to Firebase Database + */ + connectToDb() { + this.firebaseService.reconnect(); + } + + /** + * Save data on database + * @param {*} data The data wants to save on database + * @param {string} path The path of database + */ + async save(model: T): Promise { + this.connectToDb(); + + const results: DataObject = convertModelToDataObject(model); + + const saveData = this.firebaseService.save( + results.data as object, + this.defaultPath + results.id, + ); + + await timeOutConnect(saveData); + } + + /** + * + * @param {string} id The string of data object + * @param {string} path The path of database + * @returns {Object || null} Return the object if has, otherwise return null + */ + async getDataFromId( + id: string, + path: string = this.defaultPath, + ): Promise { + this.connectToDb(); + + const data = await timeOutConnect( + this.firebaseService.getDataFromId(id, path), + ); + + if (typeof data === 'object') return data; + + return null; + } + + async getDataFromProp( + property: string, + value: string, + path = this.defaultPath, + ) { + this.connectToDb(); + const data = this.firebaseService.getDataFromProp(path, property, value); + const result = >await timeOutConnect(data); + + if (result && typeof result === 'object') { + return convertDataObjectToModel(result); + } + + return null; + } + + async getAllDataFromPath(path = this.defaultPath): Promise { + this.connectToDb(); + + const results = await timeOutConnect( + this.firebaseService.getAllDataFromPath(path), + ); + + if (typeof results === 'object') { + // Convert format object + return results.map((data) => { + const tempData = data as DataObject; + + return convertDataObjectToModel(tempData); + }) as T[]; + } + + return null; + } + + async getListDataFromProp( + property: string, + value: string | number, + path: string = this.defaultPath, + ): Promise { + this.connectToDb(); + + const results = await timeOutConnect( + this.firebaseService.getListDataFromProp(path, property, value), + ); + + if (results && typeof results === 'object') { + // Convert format object + + return results.map((data) => { + const tempData = data as DataObject; + + return convertDataObjectToModel(tempData); + }) as T[]; + } + + return null; + } + + async deleteData( + id: string, + path = this.defaultPath, + ): Promise { + this.connectToDb(); + + await timeOutConnect(this.firebaseService.delete(id, path)); + } +} diff --git a/src/ts/services/firebaseService.ts b/src/ts/services/firebaseService.ts new file mode 100644 index 0000000..32557a9 --- /dev/null +++ b/src/ts/services/firebaseService.ts @@ -0,0 +1,179 @@ +import { FirebaseApp, initializeApp } from 'firebase/app'; +import { + getDatabase, + ref, + set, + goOffline, + goOnline, + onValue, + remove, + Database, +} from 'firebase/database'; +import { DATABASE_URL } from '../constants/config'; + +class FirebaseService { + app: FirebaseApp; + + db: Database; + + constructor() { + const firebaseConfig = { + databaseURL: DATABASE_URL, + }; + this.app = initializeApp(firebaseConfig); + this.db = getDatabase(this.app); + } + + /** + * Save data in database + * @param {Object} data The object need to save into database + * @param {string} path The path of database need to be save + * @returns {Promise} Return the resolves when write to database completed + */ + save(data: object, path: string): Promise { + return set(ref(this.db, path), data); + } + + delete(id: string, path: string): Promise { + return remove(ref(this.db, path + id)); + } + + /** + * Disconnect to database + */ + disconnect(): void { + goOffline(this.db); + } + + /** + * Reconnect to database + */ + reconnect(): void { + goOnline(this.db); + } + + /** + * Find id of value by property in database + * @param {string} path The path of database to be found + * @param {string} property The property of the value need to be found + * @param {value} value The value to compare in database + * @returns {Promise} Return the resolve when find completed + */ + getDataFromProp( + path: string, + property: string, + value: string, + ): Promise { + return new Promise((resolve) => { + onValue( + ref(this.db, path), + (snapshot) => { + let id: string | null = null; + let data: object | null = null; + let result: object | null = null; + + // snapshot is a type of data by Firebase define + snapshot.forEach((childSnapshot) => { + const dataTemp = childSnapshot.val(); + + if (dataTemp[property] === value) { + id = childSnapshot.key; + data = dataTemp; + } + }); + + if (id && data) { + result = { id, data }; + } + + resolve(result); + }, + { + onlyOnce: true, + }, + ); + }); + } + + /** + * Get data object from Id + * @param {string} id The id of data object + * @param {string} path The path of data save in database + * @returns {Promise} Return new Promise + */ + getDataFromId(id: string, path: string): Promise { + return new Promise((resolve) => { + onValue( + ref(this.db, path + id), + (snapshot) => { + resolve(snapshot.val()); + }, + { + onlyOnce: true, + }, + ); + }); + } + + getAllDataFromPath(path: string): Promise { + return new Promise((resolve) => { + onValue( + ref(this.db, path), + (snapshot) => { + const listData: object[] = []; + + // snapshot is a type of data by Firebase define + snapshot.forEach((childSnapshot) => { + let id: string | null = null; + let data: object | null = null; + + id = childSnapshot.key; + data = childSnapshot.val(); + + listData.push({ id, data }); + }); + + resolve(listData); + }, + { + onlyOnce: true, + }, + ); + }); + } + + getListDataFromProp( + path: string, + property: string, + value: string | number, + ): Promise { + return new Promise((resolve) => { + onValue( + ref(this.db, path), + (snapshot) => { + let id: string; + let data: object; + const listData: object[] = []; + + // snapshot is a type of data by Firebase define + snapshot.forEach((childSnapshot) => { + const dataTemp = childSnapshot.val(); + + if (dataTemp[property] === value) { + id = childSnapshot.key; + data = dataTemp; + + listData.push({ id, data }); + } + }); + resolve(listData); + }, + { + onlyOnce: true, + }, + ); + }); + } +} + +export default new FirebaseService(); diff --git a/src/ts/services/index.ts b/src/ts/services/index.ts new file mode 100644 index 0000000..5375744 --- /dev/null +++ b/src/ts/services/index.ts @@ -0,0 +1,21 @@ +import CategoryService from './categoryService'; +import TransactionService from './transactionService'; +import UserService from './userService'; +import WalletService from './walletService'; + +export default class Service { + public userService: UserService; + + public walletService: WalletService; + + public transactionService: TransactionService; + + public categoryService: CategoryService; + + constructor() { + this.userService = new UserService(); + this.walletService = new WalletService(); + this.transactionService = new TransactionService(); + this.categoryService = new CategoryService(); + } +} diff --git a/src/ts/services/localStorageService.ts b/src/ts/services/localStorageService.ts new file mode 100644 index 0000000..5339fb3 --- /dev/null +++ b/src/ts/services/localStorageService.ts @@ -0,0 +1,25 @@ +class LocalStorageService { + localStorage: Storage; + + constructor() { + this.localStorage = localStorage; + } + + add(key: string, value: string) { + this.localStorage.setItem(key, value); + } + + get(key: string): string | null { + return this.localStorage.getItem(key); + } + + remove(key: string) { + this.localStorage.removeItem(key); + } + + clear() { + this.localStorage.clear(); + } +} + +export default new LocalStorageService(); diff --git a/src/ts/services/transactionService.ts b/src/ts/services/transactionService.ts new file mode 100644 index 0000000..54d8550 --- /dev/null +++ b/src/ts/services/transactionService.ts @@ -0,0 +1,34 @@ +import Transaction from 'models/transaction'; +import CommonService from './commonService'; + +export default class TransactionService extends CommonService { + constructor() { + super(); + + this.defaultPath = 'transactions/'; + } + + /** + * Save transaction into database + * @param {Object} transaction The wallet object need to be saved into database + */ + async saveTransaction(transaction: Transaction): Promise { + await this.save(transaction); + } + + async getListTransactionByIdUser( + idUser: string, + ): Promise { + const results = await this.getListDataFromProp( + 'idUser', + idUser, + this.defaultPath, + ); + + return results || null; + } + + async deleteTransaction(idTransaction: string): Promise { + await this.deleteData(idTransaction); + } +} diff --git a/src/ts/services/userService.ts b/src/ts/services/userService.ts new file mode 100644 index 0000000..42729ed --- /dev/null +++ b/src/ts/services/userService.ts @@ -0,0 +1,112 @@ +import { LOCAL_STORAGE } from '../constants/config'; +import { createToken } from '../helpers/data'; +import User from '../models/user'; +import CommonService from './commonService'; +import LocalStorageService from './localStorageService'; + +export default class UserService { + private commonService: CommonService; + + constructor() { + this.commonService = new CommonService('users/'); + } + + /** + * Save user into database + * @param {Object} user The user object need to be saved into database + */ + async saveUser(user: User): Promise { + await this.commonService.save(user); + } + + /** + * Check user exist in database + * @param {string} email Email to find user + * @returns {boolean} Return true if find, otherwise return false + */ + async isValidUser(email: string): Promise { + const userExist = await this.getUserByEmail(email); + + return !!userExist; + } + + /** + * Get user data from email + * @param {string} email Email user + * @returns {Object || null} Return new User Object if find, otherwise return null. + */ + async getUserByEmail(email: string): Promise { + const result = await this.commonService.getDataFromProp('email', email); + + return result || null; + } + + /** + * Validate user info + * @param {string} email The email user input + * @param {*} password The password user input + * @returns {boolean} Return true if match info on database, otherwise return false + */ + async loginUser(email: string, password: string): Promise { + const user = await this.getUserByEmail(email); + + // Check password + if (user && user.password === password) { + // Create token for user + await this.createTokenUser(email); + + return true; + } + + return false; + } + + /** + * Create token for user on database + * @param {string} email The email user need to be create token + */ + async createTokenUser(email: string): Promise { + const user = await this.getUserByEmail(email); + if (user) { + const newUserData = user; + + // Add token to user object + newUserData.accessToken = createToken(); + + this.commonService.save(newUserData); + + // Add access token to local storage + LocalStorageService.add( + LOCAL_STORAGE.ACCESS_TOKEN, + newUserData.accessToken, + ); + } + } + + async getInfoUserLogin(): Promise { + // Find access token + const accessToken = LocalStorageService.get(LOCAL_STORAGE.ACCESS_TOKEN); + + if (accessToken) { + const user = await this.getUserByToken(accessToken); + + return user; + } + + return null; + } + + /** + * Get user data from token access + * @param {string} accessToken Access token user + * @returns {Object || null} Return new User Object if find, otherwise return null. + */ + async getUserByToken(accessToken: string): Promise { + const result = await this.commonService.getDataFromProp( + 'accessToken', + accessToken, + ); + + return result || null; + } +} diff --git a/src/ts/services/walletService.ts b/src/ts/services/walletService.ts new file mode 100644 index 0000000..c84a90b --- /dev/null +++ b/src/ts/services/walletService.ts @@ -0,0 +1,40 @@ +import Wallet from '../models/wallet'; +import CommonService from './commonService'; + +export default class WalletService extends CommonService { + constructor() { + super(); + + this.defaultPath = 'wallets/'; + } + + /** + * Save wallet into database + * @param {Object} wallet The wallet object need to be saved into database + */ + async saveWallet(wallet: Wallet): Promise { + await this.save(wallet); + } + + /** + * Check wallet exist in database + * @param {string} idUser The id user to find user's wallet + * @returns {boolean} Return true if find, otherwise return false + */ + async isValidWallet(idUser: string): Promise { + const wallet = await this.getWalletByIdUser(idUser); + + return !!wallet; + } + + /** + * Get wallet data from idUser + * @param {string} email The id user to find user's wallet + * @returns {Object || null} Return new Wallet Object if find, otherwise return null. + */ + async getWalletByIdUser(idUser: string): Promise { + const result = (await this.getDataFromProp('idUser', idUser)) as Wallet; + + return result || null; + } +} diff --git a/src/ts/views/authenticationView.ts b/src/ts/views/authenticationView.ts new file mode 100644 index 0000000..59ccb17 --- /dev/null +++ b/src/ts/views/authenticationView.ts @@ -0,0 +1,155 @@ +import CommonView from './commonView'; +import { TOAST, VALIDATE_FORM } from 'constants/messages'; +import { + compare2Password, + isValidPassword, + isValidateEmail, + renderRequiredText, +} from '../helpers/validatorForm'; +import { Nullable } from 'global/types'; + +export default class AuthenticationView extends CommonView { + public formEl: Nullable; + + public emailEl: Nullable; + + public messageDefault: string[]; + + public inputPasswordEl: Nullable; + + public inputPasswordConfirmEl: Nullable; + + public listError: string[]; + + constructor() { + super(); + + this.formEl = document.querySelector('.form'); + this.emailEl = document.querySelector("[name='email']"); + this.messageDefault = TOAST.ERROR_MESSAGE_DEFAULT; + this.inputPasswordEl = document.querySelector('input[name="password"]'); + this.inputPasswordConfirmEl = document.querySelector( + 'input[name="password_confirm"]', + ); + + this.listError = []; + } + + // eslint-disable-next-line class-methods-use-this + validateEmail(email: string): boolean { + if (email) { + if (!isValidateEmail(email)) { + this.listError.push(VALIDATE_FORM.INVALID_EMAIL_FORMAT); + + return false; + } + return true; + } + + if (this.emailEl) renderRequiredText('email', this.emailEl); + return false; + } + + validatePassword(password: string): boolean { + if (password) { + if (!isValidPassword(password)) { + this.listError.push(VALIDATE_FORM.PASSWORD_NOT_STRONG); + + return false; + } + + return true; + } + if (this.inputPasswordEl) + renderRequiredText('password', this.inputPasswordEl); + + return false; + } + + validatePasswordConfirm(password: string, passwordConfirm: string): boolean { + if (passwordConfirm) { + if (!compare2Password(password, passwordConfirm)) { + this.listError.push(VALIDATE_FORM.PASSWORD_NOT_MATCH); + + return false; + } + + return true; + } + + if (this.inputPasswordConfirmEl) + renderRequiredText('confirm password', this.inputPasswordConfirmEl); + + return false; + } + + /** + * Clear error message at form + */ + clearErrorMessage() { + // Reassign again to check error message element haved on page or not + const errorMessageEl = document.querySelector('.form__error-message'); + const errorTextEl = document.querySelectorAll('.error-text'); + + // If have error message on page, remove it with style error input password + if (errorMessageEl || errorTextEl.length > 0) { + if (errorMessageEl) errorMessageEl.remove(); + + if (errorTextEl) { + errorTextEl.forEach((item) => { + item.remove(); + }); + } + + // Use for 2 form + if (this.emailEl && this.inputPasswordEl) { + this.emailEl.classList.remove('error-input'); + this.inputPasswordEl.classList.remove('error-input'); + } + + // Only register form required + if (this.inputPasswordConfirmEl) + this.inputPasswordConfirmEl.classList.remove('error-input'); + } + } + + /** + * Add event listener for input field at form + */ + addHandlerInputFormChange() { + if (this.formEl) + this.formEl.addEventListener('input', () => { + this.clearErrorMessage(); + }); + } + + /** + * Show error message with error style input password. + * @param {string} message The error message you want show in form. + */ + showError(message: string[]) { + this.renderError(message); + } + + /** + * Show error message in form + * @param {string} message The message will show in form + */ + renderError(messages = this.messageDefault) { + if (messages.length > 0) { + const messageItemMarkup = messages + .map((message) => `
  • ${message}
  • `) + .join('\n'); + + const markup = ` +
      + ${messageItemMarkup} +
    + `; + + const titleEl = document.querySelector('.form__title'); + + if (titleEl) titleEl.insertAdjacentHTML('afterend', markup); + } + } +} diff --git a/src/ts/views/commonView.ts b/src/ts/views/commonView.ts new file mode 100644 index 0000000..32d2e71 --- /dev/null +++ b/src/ts/views/commonView.ts @@ -0,0 +1,164 @@ +import { Nullable } from 'global/types'; +import { MarkIcon, TypeToast } from '../constants/config'; + +export default class CommonView { + public toastDialog: Nullable = null; + + public toastIcon: Nullable = null; + + public toastBtn: Nullable = null; + + public toastTitle: Nullable = null; + + public toastContent: Nullable = null; + + public spinner: Nullable = null; + + constructor() { + this.toastDialog = document.querySelector('.dialog .toast'); + + this.spinner = null; + } + + /** + * Implement toast in site + */ + initToast() { + const markup = ` + +
    +
    +

    +

    + +
    +
    + `; + + const body = document.querySelector('body'); + + if (body) body.insertAdjacentHTML('afterbegin', markup); + + this.initToastEl(); + } + + initToastEl() { + this.toastDialog = document.querySelector('.dialog'); + + this.toastIcon = this.toastDialog + ? this.toastDialog.querySelector('.mark') + : null; + this.toastBtn = this.toastDialog + ? this.toastDialog.querySelector('.toast__redirect-btn') + : null; + this.toastTitle = this.toastDialog + ? this.toastDialog.querySelector('.toast__title') + : null; + this.toastContent = this.toastDialog + ? this.toastDialog.querySelector('.toast__message') + : null; + } + + /** + * Show or hide loader screen + */ + toggleLoaderSpinner() { + if (this.spinner) this.spinner.classList.toggle('hidden'); + } + + /** + * Add toast content + * @param {TYPE_TOAST} typeToast Type of the toast + * @param {string} title Title of toast + * @param {string} content Content of toast + * @param {string} btnContent Content of button + */ + initToastContent( + typeToast: string, + title: string, + content: string, + btnContent: string, + ) { + // Remove old typeToast class if haved + Object.keys(TypeToast).forEach((key) => { + CommonView.removeClassElement( + TypeToast[key as keyof typeof TypeToast], + this.toastDialog as HTMLBodyElement | null, + ); + }); + + // Remove old icon toast if haved + Object.keys(MarkIcon).forEach((key) => { + CommonView.removeClassElement( + MarkIcon[key as keyof typeof MarkIcon], + this.toastIcon, + ); + }); + + // Init content toast + if ( + this.toastDialog && + this.toastIcon && + this.toastTitle && + this.toastContent && + this.toastBtn + ) { + this.toastDialog.classList.add( + typeToast === TypeToast.success ? TypeToast.success : TypeToast.error, + ); + this.toastIcon.classList.add( + typeToast === TypeToast.success ? MarkIcon.success : MarkIcon.error, + ); + this.toastTitle.textContent = title; + this.toastContent.textContent = content; + this.toastBtn.textContent = btnContent; + } + } + + static removeClassElement(classEl: string, el: HTMLBodyElement | null) { + if (el && el.classList.contains(classEl)) { + el.classList.remove(classEl); + } + } + + /** + * Add event listener for toast + */ + handleEventToast() { + if (this.toastBtn) { + this.toastBtn.addEventListener('click', () => { + if (this.toastDialog) this.toastDialog.close(); + }); + } + + // Add event close dialog when click outside + if (this.toastDialog) { + this.toastDialog.addEventListener('click', (e) => { + if (this.toastDialog) { + const dialogDimensions = this.toastDialog.getBoundingClientRect(); + if ( + e.clientX < dialogDimensions.left || + e.clientX > dialogDimensions.right || + e.clientY < dialogDimensions.top || + e.clientY > dialogDimensions.bottom + ) { + this.toastDialog.close(); + } + } + }); + } + } + + /** + * Implement loader screen + */ + initLoader() { + const markup = ``; + + const body = document.querySelector('body'); + if (body) body.insertAdjacentHTML('afterbegin', markup); + + // Init element + this.spinner = document.querySelector('.loader'); + } +} diff --git a/src/ts/views/home/budgetView.ts b/src/ts/views/home/budgetView.ts new file mode 100644 index 0000000..4bcc37f --- /dev/null +++ b/src/ts/views/home/budgetView.ts @@ -0,0 +1,204 @@ +import Transaction from '../../models/transaction'; +import { renderRequiredText } from '../../helpers/validatorForm'; +import EventDataTrigger from 'helpers/evDataTrigger'; +import Wallet from 'models/wallet'; +import User from 'models/user'; +import { DEFAULT_CATEGORY } from 'constants/config'; +import { TOAST } from 'constants/messages'; +import { + IBudgetViewFunc, + Data, + Nullable, + PromiseVoid, + TError, + VoidFunc, +} from 'global/types'; + +export default class BudgetView { + budgetDialog: Nullable = null; + + addBudgetBtn: Nullable = null; + + evDataTrigger: Nullable = null; + + toggleLoaderSpinner: Nullable = null; + + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; + + loadTransactionData: Nullable = null; + + updateAmountWallet: Nullable = null; + + loadData: Nullable = null; + + showSuccessToast: Nullable<(title: string, message: string) => void> = null; + + showErrorToast: Nullable<(error: TError) => void> = null; + + wallet: Nullable = null; + + user: Nullable = null; + + constructor() { + this.budgetDialog = document.getElementById( + 'budgetDialog', + ) as HTMLDialogElement; + this.addBudgetBtn = document.getElementById('addBudget'); + + this.handlerEventBudgetView(); + } + + initFunction(func: IBudgetViewFunc) { + this.showErrorToast = func.showErrorToast; + this.showSuccessToast = func.showSuccessToast; + this.toggleLoaderSpinner = func.toggleLoaderSpinner; + this.saveTransaction = func.saveTransaction; + this.loadTransactionData = func.loadTransactionData; + this.updateAmountWallet = func.updateAmountWallet; + this.loadData = func.loadData; + + this.evDataTrigger = EventDataTrigger.Instance; + } + + subscribe() { + this.evDataTrigger!.create('budgetView', this.updateData.bind(this)); + } + + sendData() { + const data = { wallet: this.wallet! }; + + this.evDataTrigger!.onSendSignal('budgetView', data); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.user) this.user = data.user; + } + + addHandlerEventBudgetForm() { + this.budgetDialog!.addEventListener('submit', (e) => { + e.preventDefault(); + + this.clearErrorStyleBudgetForm(); + this.submitBudgetForm(); + }); + + this.budgetDialog!.addEventListener('input', () => { + this.changeBtnStyle(); + this.clearErrorStyleBudgetForm(); + }); + } + + clearErrorStyleBudgetForm() { + // Clear error style + const inputFieldEls = + this.budgetDialog!.querySelectorAll('.form__input-field'); + const errorTexts = this.budgetDialog!.querySelectorAll('.error-text'); + + inputFieldEls.forEach((item) => { + if (item.classList.contains('error-input')) + item.classList.remove('error-input'); + }); + + errorTexts.forEach((item) => { + if (item) item.remove(); + }); + } + + async submitBudgetForm(): Promise { + try { + const form = document.getElementById('formAddBudget') as HTMLFormElement; + const formAddBudget = new FormData(form); + const date = formAddBudget.get('selected_date') as string; + const amount = formAddBudget.get('amount') as string; + const note = formAddBudget.get('note') as string; + + // Validate data user input + + if (this.validateBudgetForm(date, +amount)) { + this.toggleLoaderSpinner!(); // Enable loader spinner + this.budgetDialog!.close(); // Close dialog + + const transaction = new Transaction( + '', + DEFAULT_CATEGORY.INCOME, + date, + note, + +amount, + this.wallet!.idUser, + ); + + await this.saveTransaction!(transaction); + + // Reload data + await this.loadTransactionData!(); + await this.updateAmountWallet!(); + await this.loadData!(); + + // Hide loader spinner + this.toggleLoaderSpinner!(); + + // Show success message + this.showSuccessToast!( + TOAST.ADD_TRANSACTION_SUCCESS, + TOAST.DEFAULT_MESSAGE, + ); + + (document.getElementById('formAddBudget')!).reset(); + } + } catch (error) { + this.showErrorToast!(error as TError); + } + } + + validateBudgetForm(date: string, amount: number): boolean { + const inputFieldEl = + this.budgetDialog!.querySelectorAll('.form__input-field'); + + if (!date || !amount) { + if (!date) { + renderRequiredText('date', inputFieldEl[0]); + inputFieldEl[0].classList.add('error-input'); + } + + if (!amount) { + renderRequiredText('amount', inputFieldEl[1]); + inputFieldEl[1].classList.add('error-input'); + } + + return false; + } + + return true; + } + + changeBtnStyle() { + const date = (( + this.budgetDialog!.querySelector('.input-date')! + )).value; + const amount = +(( + this.budgetDialog!.querySelector('.form__input-balance')! + )).value; + const saveBtn = this.budgetDialog!.querySelector('.form__save-btn')!; + + if (date.trim() && amount >= 1) { + saveBtn.classList.add('active'); + } else { + saveBtn.classList.remove('active'); + } + } + + handlerEventBudgetView() { + this.addBudgetBtn!.addEventListener('click', () => { + // Set default value for date input + (( + this.budgetDialog!.querySelector("[name='selected_date']") + ))!.valueAsDate = new Date(); + + this.budgetDialog!.showModal(); + }); + + this.addHandlerEventBudgetForm(); + } +} diff --git a/src/ts/views/home/categoryView.ts b/src/ts/views/home/categoryView.ts new file mode 100644 index 0000000..1124694 --- /dev/null +++ b/src/ts/views/home/categoryView.ts @@ -0,0 +1,167 @@ +import EventDataTrigger from 'helpers/evDataTrigger'; +import { REMOVE_CATEGORY } from '../../constants/config'; +import Category from 'models/category'; +import { Data, Nullable, PromiseOrNull } from 'global/types'; + +export default class CategoryView { + categoryDialog: Nullable = null; + + categoryField: Nullable = null; + + closeIcon: Nullable = null; + + getAllCategory: Nullable> = null; + + evDataTrigger: Nullable = null; + + listCategory: Nullable = null; + + categorySelected: string; + + constructor() { + this.categorySelected = ''; + + this.categoryDialog = document.getElementById( + 'categoryDialog', + ) as HTMLDialogElement; + this.categoryField = document.getElementById('selectCategory'); + this.closeIcon = document.querySelector('.close-icon') as HTMLElement; + + this.handlerEventCategoryDialog(); + this.addEventSelectCategoryDialog(); + } + + initFunction( + getAllCategory: PromiseOrNull, + evDataTrigger: EventDataTrigger, + ) { + this.getAllCategory = getAllCategory; + this.evDataTrigger = evDataTrigger; + } + + sendData() { + const data: Data = { listCategories: this.listCategory! }; + + this.evDataTrigger!.onSendSignal('categoryView', data); + } + + handlerEventCategoryDialog() { + this.categoryDialog!.addEventListener('input', () => { + setTimeout(() => { + this.searchCategory(); + }, 300); + }); + } + + /** + * Load category data + * @param {function} getAllCategory Get all category function + */ + async loadCategory(): Promise { + if (!this.listCategory) { + this.listCategory = await this.getAllCategory!(); + + this.sendData(); + } + + if (this.listCategory) { + this.renderCategoryList(); + } + } + + searchCategory() { + const searchCategoryEl: HTMLDataElement = + this.categoryDialog!.querySelector("[name='category']")!; + const searchValue = searchCategoryEl.value.trim().toLowerCase(); + let newListCategory: Category[] = []; + + if (searchValue) { + this.listCategory!.forEach((category) => { + const categoryName = category.name.trim().toLowerCase(); + + if (categoryName.includes(searchValue)) { + newListCategory.unshift(category); + } + }); + } else { + newListCategory = this.listCategory!; + } + + // Render category item + this.renderCategoryList(this.categorySelected, newListCategory); + } + + renderCategoryList( + categorySelected?: string, + listCategory = this.listCategory!, + ) { + // Remove category name unnecessary + const newListCategory = listCategory.filter( + (item) => !REMOVE_CATEGORY.includes(item.name), + ); + + const listCategoryEl = document.querySelector('.list-category'); + + listCategoryEl!.innerHTML = ''; // Remove old category item + + newListCategory.forEach((category) => { + const markup = ` +
    + ${category.name} Icon +

    ${category.name}

    +
    + `; + + listCategoryEl!.insertAdjacentHTML('afterbegin', markup); + }); + } + + addEventSelectCategoryDialog() { + const categoryListEl = document.querySelector('.list-category'); + const categoryIconEl = this.categoryField!.querySelector( + '.category-icon', + ) as HTMLImageElement; + const categoryNameEl = this.categoryField!.querySelector( + '.category-name', + ) as HTMLDataElement; + + categoryListEl!.addEventListener('click', (e) => { + const categoryItem = (e.target).closest( + '.category-item', + ) as HTMLElement; + + if (categoryItem) { + const { url } = categoryItem.dataset; + const { value } = categoryItem.dataset; + + // Set url and value into category field in transaction dialog + categoryIconEl.src = url!; + categoryNameEl.value = value!; + + // Close select category dialog + this.categoryDialog!.close(); + } + }); + + // Pass value selected to category dialog + categoryNameEl.addEventListener('click', () => { + if (categoryNameEl.value) { + // Make the keyword search category name into global + this.categorySelected = categoryNameEl.value; + + this.renderCategoryList(this.categorySelected); + } + this.categoryDialog!.showModal(); + }); + + this.closeIcon!.addEventListener('click', () => { + this.categoryDialog!.close(); + }); + } +} diff --git a/src/ts/views/home/homeView.ts b/src/ts/views/home/homeView.ts new file mode 100644 index 0000000..60d15b0 --- /dev/null +++ b/src/ts/views/home/homeView.ts @@ -0,0 +1,439 @@ +import { BTN_CONTENT, TypeToast } from '../../constants/config'; +import CommonView from '../commonView'; +import { clearAccessToken, formatNumber } from '../../helpers/data'; + +import WalletView from './walletView'; +import Wallet from 'models/wallet'; +import EventDataTrigger from 'helpers/evDataTrigger'; +import Transaction from 'models/transaction'; +import User from 'models/user'; +import { + Data, + IBudgetViewFunc, + IHomeFunc, + ITransactionViewFunc, + IWalletViewFunc, + Nullable, + PromiseOrNull, + TError, +} from 'global/types'; +import { TOAST } from 'constants/messages'; +import { redirectToLoginPage } from 'helpers/url'; +import Category from 'models/category'; +import CategoryView from './categoryView'; +import BudgetView from './budgetView'; +import TransactionView from './transactionView'; +import SummaryTabView from './summaryTabView'; +import TransactionDetail from 'models/transactionDetail'; +import TransactionTabView from './transactionTabView'; + +export default class HomeView extends CommonView { + walletView: WalletView; + + categoryView: CategoryView; + + budgetView: BudgetView; + + transactionView: TransactionView; + + summaryTabView: SummaryTabView; + + transactionTabView: TransactionTabView; + + tabs: NodeListOf; + + allContent: NodeListOf; + + cancelBtns: NodeListOf; + + dialogs: NodeListOf; + + amountInputs: NodeListOf; + + user: Nullable = null; + + wallet: Nullable = null; + + listTransactions: Transaction[] = []; + + transactionDetails: TransactionDetail[] = []; + + getInfoUserLogin: Nullable> = null; + + getWalletByIdUser: Nullable<(idUser: string) => Promise> = + null; + + getAllCategory: Nullable<() => Promise> = null; + + getAllTransactions: Nullable< + (idUser: string) => Promise + > = null; + + deleteTransaction: Nullable<(idTransaction: string) => Promise> = null; + + saveWallet: Nullable<(wallet: Wallet) => Promise> = null; + + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; + + evDataTrigger: Nullable = null; + + constructor() { + super(); + + this.tabs = document.querySelectorAll('.app__tab-item'); + this.allContent = document.querySelectorAll('.app__content-item'); + this.cancelBtns = document.querySelectorAll('.form__cancel-btn'); + this.dialogs = document.querySelectorAll('.dialog'); + + this.amountInputs = document.querySelectorAll('.form__input-balance'); + + this.walletView = new WalletView(); + this.categoryView = new CategoryView(); + this.budgetView = new BudgetView(); + this.transactionView = new TransactionView(this.categoryView); + this.summaryTabView = new SummaryTabView(); + this.transactionTabView = new TransactionTabView(this.transactionView); + + this.initToast(); + this.initLoader(); + this.handleEventToast(); + } + + // ----------------------- Init function ----------------------- // + initFunction(func: IHomeFunc) { + this.getInfoUserLogin = func.getInfoUserLogin || null; + this.getWalletByIdUser = func.getWalletByIdUser || null; + this.getAllCategory = func.getAllCategory || null; + this.getAllTransactions = func.getAllTransactions || null; + this.saveWallet = func.saveWallet || null; + this.saveTransaction = func.saveTransaction || null; + this.deleteTransaction = func.deleteTransaction || null; + + this.evDataTrigger = EventDataTrigger.Instance; + + // Init function for child view + this.initWalletViewFunction(); + this.initBudgetViewFunction(); + this.initTransactionViewFunction(); + this.initCategoryViewFunction(); + this.initSummaryTabViewFunction(); + this.initTransactionTabViewFunction(); + } + + initTransactionViewFunction() { + const func: ITransactionViewFunc = { + toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this), + deleteTransaction: this.deleteTransaction!, + loadTransactionData: this.loadTransactionData.bind(this), + updateAmountWallet: this.updateAmountWallet.bind(this), + loadData: this.loadData.bind(this), + showSuccessToast: this.showSuccessToast.bind(this), + showErrorToast: this.showErrorToast.bind(this), + saveTransaction: this.saveTransaction!, + }; + + this.transactionView.initFunction(func); + } + + initBudgetViewFunction() { + const func: IBudgetViewFunc = { + showErrorToast: this.showErrorToast.bind(this), + showSuccessToast: this.showSuccessToast.bind(this), + toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this), + saveTransaction: this.saveTransaction!.bind(this), + loadTransactionData: this.loadTransactionData.bind(this), + updateAmountWallet: this.updateAmountWallet.bind(this), + loadData: this.loadData.bind(this), + }; + + this.budgetView.initFunction(func); + } + + initCategoryViewFunction() { + this.categoryView.initFunction(this.getAllCategory!, this.evDataTrigger!); + } + + initSummaryTabViewFunction() { + this.summaryTabView.initFunction(this.evDataTrigger!); + } + + initTransactionTabViewFunction() { + this.transactionTabView.initFunction(this.evDataTrigger!); + } + + initWalletViewFunction() { + const func: IWalletViewFunc = { + toggleLoaderSpinner: this.toggleLoaderSpinner.bind(this), + saveWallet: this.saveWallet, + saveTransaction: this.saveTransaction, + loadTransactionData: this.loadTransactionData.bind(this), + loadData: this.loadData.bind(this), + loadEvent: this.loadEvent.bind(this), + showSuccessToast: this.showSuccessToast.bind(this), + showErrorToast: this.showErrorToast.bind(this), + }; + + this.walletView.initFunction(func); + } + // ----------------------- End ----------------------- // + + subscribeListenerData() { + this.subscribe(); + this.transactionView.subscribe(); + this.budgetView.subscribe(); + this.summaryTabView.subscribe(); + this.transactionTabView.subscribe(); + this.walletView.subscribe(); + } + + async loadData(): Promise { + // Send data to other class + this.sendData(); + + await this.categoryView.loadCategory(); + this.summaryTabView.load(); + this.transactionTabView.loadTransactionTab(); + + await this.loadWalletUser(); + await this.updateAmountWallet(); + } + + async loadPage(): Promise { + this.toggleLoaderSpinner(); + const user = await this.getInfoUserLogin!(); + + if (!user) { + // If user not login yet + clearAccessToken(); + window.location.replace('/login'); + } else { + // If user already login + this.user = user; + this.wallet = await this.getWalletByIdUser!(user.id); + + this.sendData(); + // Check user's wallet if have or not + if (!this.wallet) { + // Show add wallet dialog + this.walletView.showDialog(); + } else { + // Init data + await this.loadTransactionData(); + await this.loadData(); + + // Load event page + this.loadEvent(); + } + } + + this.toggleLoaderSpinner(); + } + + // ---------------------LOAD DATA---------------------// + + subscribe() { + this.evDataTrigger!.create('homeView', this.updateData.bind(this)); + } + + sendData() { + const data: Data = { + wallet: this.wallet!, + listTransactions: this.listTransactions!, + user: this.user!, + }; + + this.evDataTrigger!.onSendSignal('homeView', data); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.user) this.user = data.user; + } + + /** + * Load wallet user + */ + async loadWalletUser(): Promise { + const wallet = this.wallet + ? this.wallet + : await this.getWalletByIdUser!(this.user!.id); + const walletName = document.querySelector('.wallet__name'); + const walletPrice = document.querySelector('.wallet__price'); + const walletNameValue = wallet!.walletName; + const walletAmountValue = wallet!.inflow + wallet!.outflow; + + const sign = walletAmountValue >= 0 ? '+' : '-'; + + this.wallet = wallet; // Make wallet into global variable + + walletName!.textContent = walletNameValue; + walletPrice!.textContent = `${sign}$ ${formatNumber( + Math.abs(walletAmountValue), + )}`; // Math.abs(walletAmountValue) to keep the value always > 0 + + // Update amount wallet into database + this.saveWallet!(this.wallet!); + } + + async loadTransactionData(): Promise { + const data = await this.getAllTransactions!(this.wallet!.idUser); + + if (data) this.listTransactions = data; + + this.sendData(); + } + + async updateAmountWallet(): Promise { + let inflow = 0; + let outflow = 0; + // Init data first + this.transactionDetails = + this.transactionTabView!.loadTransactionDetailsData(); + + this.transactionDetails.forEach((transaction) => { + if (transaction.totalAmount >= 0) { + inflow += transaction.totalAmount; + } else { + outflow -= transaction.totalAmount; + } + }); + // Reassign value for wallet user; + this.wallet!.inflow = inflow; + this.wallet!.outflow = -outflow; + await this.saveWallet!(this.wallet!); + } + + // ---------------------END--------------------- // + + // ---------------------TOAST--------------------- // + showSuccessToast(title: string, message: string) { + const typeToast = TypeToast.success; + const btnContent = BTN_CONTENT.OK; + + this.initToastContent(typeToast, title, message, btnContent); + + this.toastDialog!.showModal(); + } + + /** + * Implement error toast in site + * @param {string} content The content will show in error toast + */ + showErrorToast(error: TError) { + const title = + typeof error === 'object' && error.title + ? error.title + : TOAST.DEFAULT_TITLE_ERROR_TOAST; + + const content = + typeof error === 'object' && error.message + ? error.message + : (error as string); + + this.initToastContent(TypeToast.error, title, content, BTN_CONTENT.OK); + + if (this.toastDialog && this.toastBtn) { + // Show toast + this.toastDialog.showModal(); + + // Remove event for toast button + this.toastBtn.removeEventListener('click', redirectToLoginPage); + } + } + // ---------------------END--------------------- // + + // --------------------- HANDLER EVENT --------------------- // + + loadEvent() { + this.addCommonEventPage(); + this.handlerTabsTransfer(); + } + + /** + * Handle event when click on tabs + */ + handlerTabsTransfer() { + this.tabs.forEach((tab, index) => { + tab.addEventListener('click', (e: Event) => { + this.removeActiveTab(); + tab.classList.add('active'); + + const line = document.querySelector( + '.app__line', + ) as HTMLElement; + + const eventTarget = e.target as HTMLElement; + + line.style.width = `${eventTarget.offsetWidth}px`; + line.style.left = `${eventTarget.offsetLeft}px`; + + this.allContent.forEach((content) => { + content.classList.remove('active'); + }); + this.allContent[index].classList.add('active'); + }); + }); + } + + addCommonEventPage() { + // Add event close dialog when click outside + this.dialogs.forEach((dialog) => { + dialog.addEventListener('click', (e) => { + const dialogDimensions = dialog.getBoundingClientRect(); + const mouseEvent = e as MouseEvent; + if ( + mouseEvent.clientX < dialogDimensions.left || + mouseEvent.clientX > dialogDimensions.right || + mouseEvent.clientY < dialogDimensions.top || + mouseEvent.clientY > dialogDimensions.bottom + ) { + (dialog).close(); + } + }); + }); + + this.cancelBtns.forEach((btn) => { + btn.addEventListener('click', () => { + this.closeAllDialog(); + }); + }); + + // Prevent input =,-,e into amount input + this.amountInputs.forEach((item) => { + item.addEventListener( + 'keypress', + (e) => + ['+', '-', 'e'].includes((e).key) && + e.preventDefault(), + ); + }); + + // Prevent user input at category search + const categorySearchEl = document.querySelector( + '.category-name', + ) as Element; + categorySearchEl.addEventListener('keydown', (e) => { + e.preventDefault(); + }); + + const logoutBtn = document.querySelector('.logout-text') as Element; + logoutBtn.addEventListener('click', () => { + clearAccessToken(); + + window.location.replace('/login'); + }); + } + + closeAllDialog() { + this.dialogs.forEach((dialog) => { + (dialog).close(); + }); + } + + removeActiveTab() { + this.tabs.forEach((tab) => { + tab.classList.remove('active'); + }); + } +} diff --git a/src/ts/views/home/summaryTabView.ts b/src/ts/views/home/summaryTabView.ts new file mode 100644 index 0000000..eae2560 --- /dev/null +++ b/src/ts/views/home/summaryTabView.ts @@ -0,0 +1,48 @@ +import EventDataTrigger from 'helpers/evDataTrigger'; +import { formatNumber } from '../../helpers/data'; +import { Data, Nullable } from 'global/types'; +import Wallet from 'models/wallet'; +import Transaction from 'models/transaction'; +import Category from 'models/category'; + +export default class SummaryTabView { + evDataTrigger: Nullable = null; + + wallet: Nullable = null; + + listTransactions: Transaction[] = []; + + listCategories: Category[] = []; + + initFunction(evDataTrigger: EventDataTrigger) { + this.evDataTrigger = evDataTrigger; + } + + subscribe() { + this.evDataTrigger!.create('summaryTabView', this.updateData.bind(this)); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.listTransactions) this.listTransactions = data.listTransactions; + + if (data.listCategories) this.listCategories = data.listCategories; + } + + load() { + const inflowValue = document.querySelector('.inflow__text--income')!; + const outflowValue = document.querySelector('.outflow__text--outcome')!; + const totalValue = document.querySelector('.summary__total')!; + + const { inflow } = this.wallet!; + const { outflow } = this.wallet!; + const total = inflow + outflow; + + inflowValue.textContent = `+$ ${formatNumber(inflow)}`; + outflowValue.textContent = `-$ ${formatNumber(Math.abs(outflow))}`; + totalValue.textContent = `${total >= 0 ? '+' : '-'}$ ${formatNumber( + Math.abs(total), + )}`; + } +} diff --git a/src/ts/views/home/transactionTabView.ts b/src/ts/views/home/transactionTabView.ts new file mode 100644 index 0000000..c365ea5 --- /dev/null +++ b/src/ts/views/home/transactionTabView.ts @@ -0,0 +1,197 @@ +import EventDataTrigger from 'helpers/evDataTrigger'; +import { + createTransactionDetailObject, + getAllCategoryNameInTransactions, + getAllTransactionByCategoryName, +} from '../../helpers/data'; +import { formatNumber } from '../../helpers/data'; +import TransactionView from './transactionView'; +import { Data, Nullable } from 'global/types'; +import Wallet from 'models/wallet'; +import Transaction from 'models/transaction'; +import Category from 'models/category'; +import TransactionDetail from 'models/transactionDetail'; + +export default class TransactionTabView { + transactionView: TransactionView; + + evDataTrigger: Nullable = null; + + wallet: Nullable = null; + + listTransactions: Transaction[] = []; + + listCategories: Category[] = []; + + transactionDetails: TransactionDetail[] = []; + + constructor(transactionView: TransactionView) { + this.transactionView = transactionView; + this.addEventTransactionItem(); + } + + initFunction(evDataTrigger: EventDataTrigger) { + this.evDataTrigger = evDataTrigger; + } + + subscribe() { + this.evDataTrigger!.create( + 'transactionTabView', + this.updateData.bind(this), + ); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.listTransactions) this.listTransactions = data.listTransactions; + + if (data.listCategories) this.listCategories = data.listCategories; + } + + async loadTransactionTab(): Promise { + // Load category + // Init data first + this.transactionDetails = this.loadTransactionDetailsData(); + const transactionEl = document.querySelector('.transaction')!; + const listTransactionDetailEl = + transactionEl.querySelector('.transaction__list')!; + const markup: string[] = []; + + if (this.transactionDetails) { + this.transactionDetails.forEach((transactionDetail) => { + markup.push(this.transactionDetailMarkup(transactionDetail)); + }); + } + listTransactionDetailEl.innerHTML = ''; + listTransactionDetailEl.insertAdjacentHTML('afterbegin', markup.join('\n')); + // Load event + this.addEventTransactionItem(); + } + + loadTransactionDetailsData(): TransactionDetail[] { + // Get all category user have in transactions + const listCategoryInTransaction = getAllCategoryNameInTransactions( + this.listTransactions, + ); + + // Create transactions details object + const tempList: TransactionDetail[] = listCategoryInTransaction.map( + (categoryName) => { + // Get category object from list category has been loaded. + const category = this.listCategories.filter( + (item) => item.name === categoryName, + ); + + const transactions = getAllTransactionByCategoryName( + categoryName, + this.listTransactions, + ); + + return createTransactionDetailObject( + Object.assign({}, ...category), + transactions, + ); + }, + ); + + tempList.sort( + (a, b) => parseInt(b.transactions[0].id) - parseInt(a.transactions[0].id), + ); + + return tempList; + } + + // eslint-disable-next-line class-methods-use-this + transactionDetailMarkup(transactionDetail: TransactionDetail): string { + const itemTransaction = () => { + const listMarkup: string[] = []; + + transactionDetail.transactions.forEach((transaction) => { + const markup = ` +
    +
    +

    ${transaction.day}

    +
    +

    + ${transaction.fullDateString} +

    +

    ${ + transaction.note === '' ? 'None' : transaction.note + }

    +
    +
    +

    ${transaction.amount >= 0 ? '+' : '-'}$ ${formatNumber( + Math.abs(transaction.amount), + )}

    +
    + `; + + listMarkup.push(markup); + }); + + return listMarkup.join('\n'); + }; + + return ` +
    +
    +
    +
    + Transportation icon category +
    +
    +

    + ${transactionDetail.categoryName} +

    +

    ${ + transactionDetail.totalTransaction + } Transactions

    +
    +
    +

    ${ + transactionDetail.totalAmount >= 0 ? '+' : '-' + }$ ${formatNumber(Math.abs(transactionDetail.totalAmount))}

    +
    +
    + + ${itemTransaction()} +
    + `; + } + + // eslint-disable-next-line class-methods-use-this + addEventTransactionItem() { + const transactionItemEl = document.querySelectorAll('.transaction__item'); + + if (transactionItemEl) { + transactionItemEl.forEach((item) => { + item.addEventListener('click', (e) => { + const transactionTime = (e.target).closest( + '.transaction__time', + ); + const categoryNameEl: HTMLInputElement = item.querySelector( + '.transaction__category-name', + )!; + + if (transactionTime) { + const idTransaction = (transactionTime).dataset.id!; + + // If it is income transaction, don't show dialog + if ( + categoryNameEl.textContent && + categoryNameEl.textContent.trim() !== 'Income' + ) + this.transactionView.showTransactionDialog(idTransaction); + } + }); + }); + } + } +} diff --git a/src/ts/views/home/transactionView.ts b/src/ts/views/home/transactionView.ts new file mode 100644 index 0000000..4b55389 --- /dev/null +++ b/src/ts/views/home/transactionView.ts @@ -0,0 +1,375 @@ +import Transaction from 'models/transaction'; +import defaultCategoryIcon from '../../../assets/images/question-icon.svg'; +import CategoryView from './categoryView'; +import EventDataTrigger from 'helpers/evDataTrigger'; +import { + Data, + ITransactionViewFunc, + Nullable, + PromiseVoid, + TError, + VoidFunc, +} from 'global/types'; +import Wallet from 'models/wallet'; +import Category from 'models/category'; +import { TOAST } from 'constants/messages'; +import { renderRequiredText } from 'helpers/validatorForm'; + +export default class TransactionView { + wallet: Nullable = null; + + listTransactions: Transaction[] = []; + + listCategories: Category[] = []; + + categoryView: CategoryView; + + addTransactionBtn: Nullable = null; + + transactionDialog: Nullable = null; + + transactionForm: Nullable = null; + + toggleLoaderSpinner: Nullable = null; + + deleteTransaction: Nullable<(idTransaction: string) => Promise> = null; + + loadTransactionData: Nullable = null; + + updateAmountWallet: Nullable = null; + + loadData: Nullable = null; + + showSuccessToast: ((title: string, message: string) => void) | null = null; + + showErrorToast: ((error: TError) => void) | null = null; + + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; + + evDataTrigger: EventDataTrigger | null = null; + + constructor(categoryView: CategoryView) { + this.addTransactionBtn = document.getElementById('addTransaction'); + this.transactionDialog = document.getElementById( + 'transactionDialog', + ) as HTMLDialogElement; + this.transactionForm = ( + document.getElementById('formAddTransaction') + ); + + this.handlerEventTransactionDialog(); + + this.categoryView = categoryView; + } + + initFunction(func: ITransactionViewFunc) { + this.toggleLoaderSpinner = func.toggleLoaderSpinner; + this.deleteTransaction = func.deleteTransaction; + this.loadTransactionData = func.loadTransactionData; + this.updateAmountWallet = func.updateAmountWallet; + this.loadData = func.loadData; + this.showSuccessToast = func.showSuccessToast; + this.showErrorToast = func.showErrorToast; + this.saveTransaction = func.saveTransaction; + + this.evDataTrigger = EventDataTrigger.Instance; + } + + subscribe() { + this.evDataTrigger!.create('transactionView', this.updateData.bind(this)); + } + + sendData() { + const data: Data = { + wallet: this.wallet!, + listTransactions: this.listTransactions!, + }; + + this.evDataTrigger!.onSendSignal('transactionView', data); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.listTransactions) this.listTransactions = data.listTransactions; + + if (data.listCategories) this.listCategories = data.listCategories; + } + + handlerEventTransactionDialog() { + this.transactionDialog!.addEventListener('submit', (e) => { + e.preventDefault(); + this.clearErrorTransactionDialog(); + this.submitTransactionDialog(); + }); + + this.transactionDialog!.addEventListener('input', () => { + this.changeBtnStyleTransactionDialog(); + this.clearErrorTransactionDialog(); + }); + + // Add delete transaction event + this.deleteTransactionEvent(); + + this.addTransactionBtn!.addEventListener('click', () => { + this.showTransactionDialog(); + }); + + this.handlerCategoryFieldEvent(); + } + + handlerCategoryFieldEvent() { + const categoryField = this.transactionForm!.querySelector( + "[name='category_name']", + ); + + categoryField!.addEventListener('click', () => { + this.clearErrorTransactionDialog(); + }); + } + + clearErrorTransactionDialog() { + // Clear error style + const inputFieldEls = + this.transactionDialog!.querySelectorAll('.form__input-field'); + const errorTextEls = + this.transactionDialog!.querySelectorAll('.error-text'); + + inputFieldEls.forEach((item) => { + if (item.classList.contains('error-input')) + item.classList.remove('error-input'); + }); + errorTextEls.forEach((item) => { + if (item) item.remove(); + }); + } + + deleteTransactionEvent() { + const deleteTransactionBtn = this.transactionDialog!.querySelector( + '.form__delete-btn', + ) as Element; + + deleteTransactionBtn.addEventListener('click', async () => { + const idEl = this.transactionDialog!.querySelector( + "[name='id_transaction']", + ) as HTMLDataElement; + + if (idEl.value) { + try { + this.transactionDialog!.close(); + this.toggleLoaderSpinner!(); + + await this.deleteTransaction!(idEl.value); + + // Reload data + await this.loadTransactionData!(); + await this.updateAmountWallet!(); + await this.loadData!(); + + this.showSuccessToast!('Delete success!', TOAST.DEFAULT_MESSAGE); + } catch (error) { + this.showErrorToast!(error as TError); + } + this.toggleLoaderSpinner!(); + } + }); + } + + changeBtnStyleTransactionDialog() { + const dateInput = (( + this.transactionDialog!.querySelector("[name='selected_date']") + )).value; + const categoryName = (( + this.transactionDialog!.querySelector("[name='category_name']") + )).value; + const amountInput = +(( + this.transactionDialog!.querySelector("[name='amount']") + )).value; + const saveBtn = this.transactionDialog!.querySelector('.form__save-btn')!; + + saveBtn.classList.toggle( + 'active', + (dateInput && categoryName && amountInput >= 1), + ); + } + + initValueTransactionDialog(idTransaction: string | null) { + let categoryName: string; + + if (idTransaction) { + // Get transaction object + const transactionArr = this.listTransactions.filter( + (obj) => obj.id === idTransaction, + ); + const transaction = Object.assign({}, ...transactionArr); + // Get category object + const categoryArr = this.listCategories.filter( + (obj) => obj.name === transaction.categoryName, + ); + const category = Object.assign({}, ...categoryArr); + + const idEl = ( + this.transactionDialog!.querySelector("[name='id_transaction']") + ); + const dateEl = ( + this.transactionDialog!.querySelector("[name='selected_date']"!) + ); + const categoryEl = ( + this.transactionDialog!.querySelector("[name='category_name']") + ); + const amountEl = ( + this.transactionDialog!.querySelector("[name='amount']") + ); + const noteEl = ( + this.transactionDialog!.querySelector("[name='note']") + ); + const iconEl = ( + this.transactionDialog!.querySelector('.category-icon') + ); + + idEl.value = transaction.id; + dateEl.value = transaction.date; + categoryEl.value = transaction.categoryName; + amountEl.value = Math.abs(transaction.amount).toString(); + noteEl.value = transaction.note; + iconEl.src = category.url; + + categoryName = categoryEl.value; + } + + // Show delete button only if it is a edit form and not a income transaction + const deleteBtn = + this.transactionDialog!.querySelector('.form__delete-btn')!; + const showDeleteBtn = () => { + return idTransaction && categoryName !== 'Income'; + }; + + deleteBtn.classList.toggle('hide', !showDeleteBtn()); + } + + async submitTransactionDialog(): Promise { + try { + const dateEl = ( + this.transactionForm!.querySelector("[name='selected_date']") + ); + const categoryNameEl = ( + this.transactionForm!.querySelector("[name='category_name']") + ); + const amountEl = ( + this.transactionForm!.querySelector("[name='amount']") + ); + const noteEl = ( + this.transactionForm!.querySelector("[name='note']") + ); + const idEl = ( + this.transactionForm!.querySelector("[name='id_transaction']") + ); + const amount = + categoryNameEl.value === 'Income' ? +amountEl.value : -+amountEl.value; // Check if this is a income transaction, amount must plus + + // Validate data user input + if ( + this.validateTransactionForm(dateEl.value, categoryNameEl.value, amount) + ) { + this.toggleLoaderSpinner!(); + this.transactionDialog!.close(); + + const transaction = new Transaction( + idEl.value, + categoryNameEl.value, + dateEl.value, + noteEl.value, + +amount, + this.wallet!.idUser, + ); + + await this.saveTransaction!(transaction); + + // Reload data + await this.loadTransactionData!(); + await this.updateAmountWallet!(); + await this.loadData!(); + + if (!idEl.value) { + // Add success + this.showSuccessToast!( + TOAST.ADD_TRANSACTION_SUCCESS, + TOAST.DEFAULT_MESSAGE, + ); + } else { + // Update success + this.showSuccessToast!( + TOAST.UPDATE_TRANSACTION_SUCCESS, + TOAST.DEFAULT_MESSAGE, + ); + } + + this.toggleLoaderSpinner!(); + this.clearInputTransactionForm(); + } + } catch (error) { + this.showErrorToast!(error as TError); + this.toggleLoaderSpinner!(); + } + } + + validateTransactionForm( + date: string, + categoryName: string, + amount: number, + ): boolean { + const inputFieldEls = + this.transactionDialog!.querySelectorAll('.form__input-field'); + + if (!date || !categoryName || !amount) { + if (!date) { + renderRequiredText('date', inputFieldEls[0]); + inputFieldEls[0].classList.add('error-input'); + } + + if (!categoryName) { + renderRequiredText('category', inputFieldEls[1]); + inputFieldEls[1].classList.add('error-input'); + } + + if (!amount) { + renderRequiredText('amount', inputFieldEls[2]); + inputFieldEls[2].classList.add('error-input'); + } + + return false; + } + + return true; + } + + clearInputTransactionForm() { + const categoryIcon = ( + this.transactionForm!.querySelector('.category-icon') + ); + + categoryIcon.src = defaultCategoryIcon; + const keySearchCategory: string = ''; // Delete keyword search + this.categoryView.renderCategoryList( + keySearchCategory, + this.listCategories, + ); + this.transactionForm!.reset(); + } + + showTransactionDialog(idTransaction: string | null = null) { + this.clearInputTransactionForm(); + + // Init data transaction to dialog + this.initValueTransactionDialog(idTransaction); + + if (!idTransaction) + (( + this.transactionDialog!.querySelector("[name='selected_date']") + )).valueAsDate = new Date(); // Set default value for date input + + // Change style submit btn + this.changeBtnStyleTransactionDialog(); + this.transactionDialog!.showModal(); + } +} diff --git a/src/ts/views/home/walletView.ts b/src/ts/views/home/walletView.ts new file mode 100644 index 0000000..8954740 --- /dev/null +++ b/src/ts/views/home/walletView.ts @@ -0,0 +1,198 @@ +import Transaction from '../../models/transaction'; +import Wallet from '../../models/wallet'; +import { renderRequiredText } from '../../helpers/validatorForm'; +import EventDataTrigger from 'helpers/evDataTrigger'; +import { + Data, + IWalletViewFunc, + Nullable, + PromiseVoid, + TError, + VoidFunc, +} from 'global/types'; +import User from 'models/user'; +import { FIRST_ADD_WALLET_NOTE } from 'constants/defaultVariable'; +import { TOAST } from 'constants/messages'; + +export default class WalletView { + walletDialog: Nullable = null; + + evDataTrigger: Nullable = null; + + toggleLoaderSpinner: Nullable = null; + + saveWallet: Nullable<(wallet: Wallet) => Promise> = null; + + saveTransaction: Nullable<(transaction: Transaction) => Promise> = null; + + loadTransactionData: Nullable = null; + + loadData: Nullable = null; + + loadEvent: Nullable = null; + + showSuccessToast: ((title: string, message: string) => void) | null = null; + + showErrorToast: ((error: TError) => void) | null = null; + + user: User | null = null; + + wallet: Wallet | null = null; + + constructor() { + this.walletDialog = document.getElementById( + 'walletDialog', + ) as HTMLDialogElement; + + this.addHandlerEventWalletForm(); + } + + initFunction(func: IWalletViewFunc) { + this.toggleLoaderSpinner = func.toggleLoaderSpinner; + this.saveWallet = func.saveWallet; + this.saveTransaction = func.saveTransaction; + this.loadTransactionData = func.loadTransactionData; + this.loadData = func.loadData; + this.loadEvent = func.loadEvent; + this.showSuccessToast = func.showSuccessToast; + this.showErrorToast = func.showErrorToast; + + this.evDataTrigger = EventDataTrigger.Instance; + } + + subscribe() { + this.evDataTrigger!.create('walletView', this.updateData.bind(this)); + } + + sendData() { + const data = { + wallet: this.wallet!, + user: this.user!, + }; + + this.evDataTrigger!.onSendSignal('walletView', data); + } + + updateData(data: Data) { + if (data.wallet) this.wallet = data.wallet; + + if (data.user) this.user = data.user; + } + + showDialog() { + this.walletDialog!.showModal(); + } + + addHandlerEventWalletForm() { + this.walletDialog!.addEventListener('submit', (e) => { + e.preventDefault(); + + this.clearErrorStyleWalletDialog(); + this.submitWalletForm(); + }); + + this.walletDialog!.addEventListener('input', (e) => { + const bodyDialog = (e.target!).closest('.dialog__body'); + + this.changeBtnStyleWalletDialog(bodyDialog!); + this.clearErrorStyleWalletDialog(); + }); + } + + clearErrorStyleWalletDialog() { + const inputFieldEls = + this.walletDialog!.querySelectorAll('.form__input-field'); + const errorTextEls = this.walletDialog!.querySelectorAll('.error-text'); + + inputFieldEls.forEach((item) => { + if (item.classList.contains('error-input')) + item.classList.remove('error-input'); + }); + + errorTextEls.forEach((item) => { + if (item) item.remove(); + }); + } + + async submitWalletForm(): Promise { + try { + // Wallet info + const form = document.getElementById('walletForm') as HTMLFormElement; + const walletForm = new FormData(form); + const walletName = walletForm.get('walletName') as string; + const amount = walletForm.get('amount') as string; + + if (this.validateWalletDialog(walletName, +amount)) { + this.walletDialog!.close(); + this.toggleLoaderSpinner!(); + + const wallet = new Wallet('', walletName, +amount, 0, this.user!.id); + this.wallet = wallet; + + this.sendData(); + + await this.saveWallet!(wallet); + // Transaction info + const transaction = new Transaction( + '', + 'Income', + new Date().toISOString().slice(0, 10), + FIRST_ADD_WALLET_NOTE, + +amount, + this.user!.id, + ); + + await this.saveTransaction!(transaction); + // Load data and event + await this.loadTransactionData!(); + await this.loadData!(); + this.loadEvent!(); + + this.showSuccessToast!(TOAST.ADD_WALLET_SUCCESS, TOAST.DEFAULT_MESSAGE); + + this.toggleLoaderSpinner!(); + } + } catch (error) { + // Show toast error + this.showErrorToast!(error as TError); + this.toggleLoaderSpinner!(); + } + } + + validateWalletDialog(walletName: string, amount: number): boolean { + const inputFieldEls = + this.walletDialog!.querySelectorAll('.form__input-field'); + + if (!walletName || !amount) { + if (!walletName) { + renderRequiredText('wallet name', inputFieldEls[0]); + inputFieldEls[0].classList.add('error-input'); + } + + if (!amount) { + renderRequiredText('amount', inputFieldEls[2]); + inputFieldEls[2].classList.add('error-input'); + } + + return false; + } + + return true; + } + + changeBtnStyleWalletDialog(bodyDialog: Element) { + const walletName = (( + bodyDialog.querySelector('.form__input-text') + ))!.value; + const amount = +(( + bodyDialog.querySelector('.form__input-balance')! + )).value; + const saveBtn = bodyDialog.querySelector('.form__save-btn'); + + if (walletName.length >= 3 && amount >= 1) { + saveBtn!.classList.add('active'); + } else { + saveBtn!.classList.remove('active'); + } + } +} diff --git a/src/ts/views/index.ts b/src/ts/views/index.ts new file mode 100644 index 0000000..af1b6a4 --- /dev/null +++ b/src/ts/views/index.ts @@ -0,0 +1,28 @@ +import { getSubdirectoryURL } from 'helpers/url'; +import LoginView from './loginView'; +import RegisterView from './registerView'; +import { URL } from 'constants/config'; +import HomeView from './home/homeView'; +import { Nullable } from 'global/types'; + +export default class View { + public registerView: Nullable = null; + + public loginView: Nullable = null; + + public homeView: Nullable = null; + + constructor() { + switch (getSubdirectoryURL()) { + case URL.LOGIN: + this.loginView = new LoginView(); + break; + case URL.REGISTER: + this.registerView = new RegisterView(); + break; + case URL.HOME: + this.homeView = new HomeView(); + default: + } + } +} diff --git a/src/ts/views/loginView.ts b/src/ts/views/loginView.ts new file mode 100644 index 0000000..e581b55 --- /dev/null +++ b/src/ts/views/loginView.ts @@ -0,0 +1,129 @@ +import AuthenticationView from './authenticationView'; +import { TypeToast, BTN_CONTENT } from '../constants/config'; +import User from 'models/user'; +import { TOAST, VALIDATE_FORM } from 'constants/messages'; +import { CustomError, Nullable, PromiseOrNull, TError } from 'global/types'; +import { redirectToLoginPage } from 'helpers/url'; + +export default class LoginView extends AuthenticationView { + constructor() { + super(); + + this.initToast(); + this.initLoader(); + this.handleEventToast(); + } + + async loadPage(getInfoUserLogin: PromiseOrNull) { + this.toggleLoaderSpinner(); + const user = await getInfoUserLogin(); + if (user) { + window.location.replace('/'); + } + this.toggleLoaderSpinner(); + } + + /** + * Implement error toast in site + * @param {string} content The content will show in error toast + */ + initErrorToast(error: TError) { + const title = + typeof error === 'object' && error.title + ? error.title + : TOAST.DEFAULT_TITLE_ERROR_TOAST; + + const content = + typeof error === 'object' && error.message + ? error.message + : (error as string); + + this.initToastContent(TypeToast.error, title, content, BTN_CONTENT.OK); + + if (this.toastDialog && this.toastBtn) { + // Show toast + this.toastDialog.showModal(); + + // Remove event for toast button + this.toastBtn.removeEventListener('click', redirectToLoginPage); + } + } + + /** + * Add event listener for form input + * @param {Function} validateUser The function need to be set event + */ + addHandlerForm( + loginUser: (email: string, password: string) => Promise, + ) { + if (this.formEl) + this.formEl.addEventListener('submit', (e: Event) => { + e.preventDefault(); + this.clearErrorMessage(); + this.submitForm(loginUser, e); + }); + } + + /** + * The action when submit form + * @param {Function} loginUser The function need to be set event + * * @param {event} event The event target + */ + async submitForm( + loginUser: (email: string, password: string) => Promise, + event: Event, + ) { + try { + // Load spinner + this.toggleLoaderSpinner(); + // Get data from form + const userInput = this.validateForm(event); + if (userInput) { + // Check user exist + const results = await loginUser(userInput.email, userInput.password); + if (results) { + window.location.replace('/'); + return; + } + throw new CustomError( + VALIDATE_FORM.ERROR_CREDENTIAL.title, + VALIDATE_FORM.ERROR_CREDENTIAL.message, + ); + } + } catch (error) { + // Show toast error + this.initErrorToast(error as TError); + } + // Close spinner + this.toggleLoaderSpinner(); + } + + /** + * Get data from user input + * @returns {Object || null} Return object or null + */ + validateForm(event: Event): Nullable { + if (event.target) { + const formData = new FormData(event.target as HTMLFormElement); + const email = formData.get('email') as string; + const password = formData.get('password') as string; + + // Validate user input + this.listError = []; // Reset list error + const emailValid = this.validateEmail(email); + const passwordValid = this.validatePassword(password); + + // Show error style + if (this.emailEl && this.inputPasswordEl) { + this.emailEl.classList.toggle('error-input', !emailValid); + this.inputPasswordEl.classList.toggle('error-input', !passwordValid); + if (emailValid && passwordValid) { + return new User('', email, password); + } + } + } + + this.showError(this.listError); + return null; + } +} diff --git a/src/ts/views/registerView.ts b/src/ts/views/registerView.ts new file mode 100644 index 0000000..3cda090 --- /dev/null +++ b/src/ts/views/registerView.ts @@ -0,0 +1,188 @@ +import { TypeToast, BTN_CONTENT } from '../constants/config'; +import AuthenticationView from './authenticationView'; +import User from '../models/user'; +import { redirectToLoginPage } from '../helpers/url'; +import { TOAST } from 'constants/messages'; +import { Nullable, PromiseOrNull, TError } from 'global/types'; + +interface UserInput { + email: string; + password: string; + passwordConfirm: string; +} + +export default class RegisterView extends AuthenticationView { + constructor() { + super(); + + this.initToast(); + this.initLoader(); + this.handleEventToast(); + + this.toastBtn = document.querySelector('.toast__redirect-btn'); + } + + async loadPage(getInfoUserLogin: PromiseOrNull) { + this.toggleLoaderSpinner(); + + const user = await getInfoUserLogin(); + + if (user) { + window.location.replace('/'); + } + + this.toggleLoaderSpinner(); + } + + /** + * Get data from user input + * @returns {Object || null} Return object or null + */ + getUserFromForm(): Nullable { + const form = document.getElementById('registerForm') as HTMLFormElement; + const formData = new FormData(form); + const email = formData.get('email') as string; + const password = formData.get('password') as string; + const passwordConfirm = formData.get('password_confirm') as string; + + const userInput: UserInput = { + email, + password, + passwordConfirm, + }; + + const result = this.validateForm(userInput); + + if (result) { + return new User('', email, password); + } + + return null; + } + + validateForm(userInput: UserInput): boolean { + // Validate user input + this.listError = []; // Reset list error + const emailValid = this.validateEmail(userInput.email); + const passwordValid = this.validatePassword(userInput.password); + const passwordConfirmValid = this.validatePasswordConfirm( + userInput.password, + userInput.passwordConfirm, + ); + + // Show error style + if (this.emailEl && this.inputPasswordEl && this.inputPasswordConfirmEl) { + this.emailEl.classList.toggle('error-input', !emailValid); + this.inputPasswordEl.classList.toggle('error-input', !passwordValid); + this.inputPasswordConfirmEl.classList.toggle( + 'error-input', + !passwordConfirmValid, + ); + } + + this.showError(this.listError); + + return emailValid && passwordValid && passwordConfirmValid; + } + + /** + * Implement register success toast in site + */ + showRegisterSuccessToast() { + const typeToast = TypeToast.success; + const title = TOAST.REGISTER_SUCCESS; + const content = TOAST.DEFAULT_MESSAGE; + const btnContent = BTN_CONTENT.OK; + + this.initToastContent(typeToast, title, content, btnContent); + + // Show toast + if (this.toastDialog) this.toastDialog.showModal(); + + // Add event for toast button + if (this.toastBtn) + this.toastBtn.addEventListener('click', redirectToLoginPage); + } + + /** + * Implement error toast in site + * @param {string} content The content will show in error toast + */ + initErrorToast(error: TError) { + const title = + typeof error === 'object' && error.title + ? error.title + : TOAST.DEFAULT_TITLE_ERROR_TOAST; + + const content = + typeof error === 'object' && error.message + ? error.message + : (error as string); + + this.initToastContent(TypeToast.error, title, content, BTN_CONTENT.OK); + + if (this.toastDialog && this.toastBtn) { + // Show toast + this.toastDialog.showModal(); + + // Remove event for toast button + this.toastBtn.removeEventListener('click', redirectToLoginPage); + } + } + + /** + * Add event listener for form input + * @param {Function} handler The function need to be set event + */ + addHandlerForm( + checkExistUser: (email: string) => Promise, + saveUser: (user: User) => Promise, + ) { + if (this.formEl) { + this.formEl.addEventListener('submit', async (e) => { + e.preventDefault(); + this.clearErrorMessage(); + await this.submitForm(checkExistUser, saveUser); + }); + } + } + + async submitForm( + checkExistUser: (email: string) => Promise, + saveUser: (user: User) => Promise, + ): Promise { + try { + // Load spinner + this.toggleLoaderSpinner(); + + // Get validate form + const user = this.getUserFromForm(); + + // Save user + if (user) { + // Check user exist + const userExist = await checkExistUser(user.email); + if (userExist) { + throw Error(TOAST.USER_EXIST_ERROR); + } else { + await saveUser(user); + // Show toast success + this.showRegisterSuccessToast(); + + // Clear form + const formEl = document.getElementById( + 'registerForm', + ) as HTMLFormElement; + + if (formEl) formEl.reset(); + } + } + } catch (error) { + // Show toast error + this.initErrorToast(error as TError); + } + + // Close spinner + this.toggleLoaderSpinner(); + } +} diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 0000000..c8722d7 --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["./**/*.ts", "./**/*.js", "./.*.js"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f6aca66 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + /* Language and Environment */ + "target": "ES2015" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": [ + "dom", + "ES2017", + "dom.iterable", + "scripthost" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "baseUrl": "./", + "paths": { + "*": ["./src/ts/*"] + }, + "experimentalDecorators": true /* Enable experimental support for legacy experimental decorators. */, + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + "removeComments": true /* Disable emitting comments. */, + "noEmitOnError": true /* Disable emitting files if any type checking errors are reported. */, + "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. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..bd6fd8f --- /dev/null +++ b/vercel.json @@ -0,0 +1,3 @@ +{ + "cleanUrls": true +}