diff --git a/pom.xml b/pom.xml index 7c63610..34f4cc6 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ com.h2database h2 + 2.1.212 diff --git a/railsignal-app/.env.development b/railsignal-app/.env.development new file mode 100644 index 0000000..430da52 --- /dev/null +++ b/railsignal-app/.env.development @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:8080/api \ No newline at end of file diff --git a/railsignal-app/.eslintrc.cjs b/railsignal-app/.eslintrc.cjs new file mode 100644 index 0000000..deed24f --- /dev/null +++ b/railsignal-app/.eslintrc.cjs @@ -0,0 +1,11 @@ +/* eslint-env node */ +module.exports = { + "root": true, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "env": { + "vue/setup-compiler-macros": true + } +} diff --git a/railsignal-app/.gitignore b/railsignal-app/.gitignore new file mode 100644 index 0000000..38adffa --- /dev/null +++ b/railsignal-app/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/railsignal-app/README.md b/railsignal-app/README.md new file mode 100644 index 0000000..6e6e3ef --- /dev/null +++ b/railsignal-app/README.md @@ -0,0 +1,35 @@ +# railsignal-app + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin). + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/railsignal-app/index.html b/railsignal-app/index.html new file mode 100644 index 0000000..e6c5ec9 --- /dev/null +++ b/railsignal-app/index.html @@ -0,0 +1,13 @@ + + + + + + + RailSignal + + +
+ + + diff --git a/railsignal-app/package-lock.json b/railsignal-app/package-lock.json new file mode 100644 index 0000000..98c6a16 --- /dev/null +++ b/railsignal-app/package-lock.json @@ -0,0 +1,3192 @@ +{ + "name": "railsignal-app", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "railsignal-app", + "version": "0.0.0", + "dependencies": { + "axios": "^0.27.2", + "pinia": "^2.0.14", + "three": "^0.140.0", + "vue": "^3.2.33", + "vue-router": "^4.0.14" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^2.3.1", + "eslint": "^8.5.0", + "eslint-plugin-vue": "^8.2.0", + "vite": "^2.9.5" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", + "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "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/@vitejs/plugin-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.2.tgz", + "integrity": "sha512-umyypfSHS4kQLdYAnJHhaASq7FRzNCdvcRoQ3uYGNk1/M4a+hXUd7ysN7BLhCrWH6uBokyCkFeUAaFDzSaaSrQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "vite": "^2.5.10", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", + "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz", + "integrity": "sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==", + "dependencies": { + "@vue/compiler-core": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.33.tgz", + "integrity": "sha512-H8D0WqagCr295pQjUYyO8P3IejM3vEzeCO1apzByAEaAR/WimhMYczHfZVvlCE/9yBaEu/eu9RdiWr0kF8b71Q==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.33", + "@vue/compiler-dom": "3.2.33", + "@vue/compiler-ssr": "3.2.33", + "@vue/reactivity-transform": "3.2.33", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.33.tgz", + "integrity": "sha512-XQh1Xdk3VquDpXsnoCd7JnMoWec9CfAzQDQsaMcSU79OrrO2PNR0ErlIjm/mGq3GmBfkQjzZACV+7GhfRB8xMQ==", + "dependencies": { + "@vue/compiler-dom": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", + "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" + }, + "node_modules/@vue/reactivity": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.33.tgz", + "integrity": "sha512-62Sq0mp9/0bLmDuxuLD5CIaMG2susFAGARLuZ/5jkU1FCf9EDbwUuF+BO8Ub3Rbodx0ziIecM/NsmyjardBxfQ==", + "dependencies": { + "@vue/shared": "3.2.33" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.33.tgz", + "integrity": "sha512-4UL5KOIvSQb254aqenW4q34qMXbfZcmEsV/yVidLUgvwYQQ/D21bGX3DlgPUGI3c4C+iOnNmDCkIxkILoX/Pyw==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.33", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.33.tgz", + "integrity": "sha512-N2D2vfaXsBPhzCV3JsXQa2NECjxP3eXgZlFqKh4tgakp3iX6LCGv76DLlc+IfFZq+TW10Y8QUfeihXOupJ1dGw==", + "dependencies": { + "@vue/reactivity": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.33.tgz", + "integrity": "sha512-LSrJ6W7CZTSUygX5s8aFkraDWlO6K4geOwA3quFF2O+hC3QuAMZt/0Xb7JKE3C4JD4pFwCSO7oCrZmZ0BIJUnw==", + "dependencies": { + "@vue/runtime-core": "3.2.33", + "@vue/shared": "3.2.33", + "csstype": "^2.6.8" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.33.tgz", + "integrity": "sha512-4jpJHRD4ORv8PlbYi+/MfP8ec1okz6rybe36MdpkDrGIdEItHEUyaHSKvz+ptNEyQpALmmVfRteHkU9F8vxOew==", + "dependencies": { + "@vue/compiler-ssr": "3.2.33", + "@vue/shared": "3.2.33" + }, + "peerDependencies": { + "vue": "3.2.33" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", + "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "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/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "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/esbuild": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz", + "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.38", + "esbuild-android-arm64": "0.14.38", + "esbuild-darwin-64": "0.14.38", + "esbuild-darwin-arm64": "0.14.38", + "esbuild-freebsd-64": "0.14.38", + "esbuild-freebsd-arm64": "0.14.38", + "esbuild-linux-32": "0.14.38", + "esbuild-linux-64": "0.14.38", + "esbuild-linux-arm": "0.14.38", + "esbuild-linux-arm64": "0.14.38", + "esbuild-linux-mips64le": "0.14.38", + "esbuild-linux-ppc64le": "0.14.38", + "esbuild-linux-riscv64": "0.14.38", + "esbuild-linux-s390x": "0.14.38", + "esbuild-netbsd-64": "0.14.38", + "esbuild-openbsd-64": "0.14.38", + "esbuild-sunos-64": "0.14.38", + "esbuild-windows-32": "0.14.38", + "esbuild-windows-64": "0.14.38", + "esbuild-windows-arm64": "0.14.38" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz", + "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz", + "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz", + "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz", + "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz", + "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz", + "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz", + "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz", + "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz", + "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz", + "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz", + "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz", + "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz", + "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz", + "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz", + "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz", + "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz", + "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz", + "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz", + "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz", + "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "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.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "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-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-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": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "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/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "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.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "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": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/pinia": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.14.tgz", + "integrity": "sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA==", + "dependencies": { + "@vue/devtools-api": "^6.1.4", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.2.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.4.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", + "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.3", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.72.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.72.0.tgz", + "integrity": "sha512-KqtR2YcO35/KKijg4nx4STO3569aqCUeGRkKWnJ6r+AvBBrVY9L4pmf4NHVrQr4mTOq6msbohflxr2kpihhaOA==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/three": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", + "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==" + }, + "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vite": { + "version": "2.9.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.8.tgz", + "integrity": "sha512-zsBGwn5UT3YS0NLSJ7hnR54+vUKfgzMUh/Z9CxF1YKEBVIe213+63jrFLmZphgGI5zXwQCSmqIdbPuE8NJywPw==", + "dev": true, + "dependencies": { + "esbuild": "^0.14.27", + "postcss": "^8.4.13", + "resolve": "^1.22.0", + "rollup": "^2.59.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": ">=12.2.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "less": "*", + "sass": "*", + "stylus": "*" + }, + "peerDependenciesMeta": { + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.33.tgz", + "integrity": "sha512-si1ExAlDUrLSIg/V7D/GgA4twJwfsfgG+t9w10z38HhL/HA07132pUQ2KuwAo8qbCyMJ9e6OqrmWrOCr+jW7ZQ==", + "dependencies": { + "@vue/compiler-dom": "3.2.33", + "@vue/compiler-sfc": "3.2.33", + "@vue/runtime-dom": "3.2.33", + "@vue/server-renderer": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", + "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", + "dependencies": { + "@vue/devtools-api": "^6.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.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/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + }, + "dependencies": { + "@babel/parser": { + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", + "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" + }, + "@eslint/eslintrc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@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 + }, + "@vitejs/plugin-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.2.tgz", + "integrity": "sha512-umyypfSHS4kQLdYAnJHhaASq7FRzNCdvcRoQ3uYGNk1/M4a+hXUd7ysN7BLhCrWH6uBokyCkFeUAaFDzSaaSrQ==", + "dev": true, + "requires": {} + }, + "@vue/compiler-core": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.33.tgz", + "integrity": "sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz", + "integrity": "sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==", + "requires": { + "@vue/compiler-core": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "@vue/compiler-sfc": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.33.tgz", + "integrity": "sha512-H8D0WqagCr295pQjUYyO8P3IejM3vEzeCO1apzByAEaAR/WimhMYczHfZVvlCE/9yBaEu/eu9RdiWr0kF8b71Q==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.33", + "@vue/compiler-dom": "3.2.33", + "@vue/compiler-ssr": "3.2.33", + "@vue/reactivity-transform": "3.2.33", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.33.tgz", + "integrity": "sha512-XQh1Xdk3VquDpXsnoCd7JnMoWec9CfAzQDQsaMcSU79OrrO2PNR0ErlIjm/mGq3GmBfkQjzZACV+7GhfRB8xMQ==", + "requires": { + "@vue/compiler-dom": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "@vue/devtools-api": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz", + "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==" + }, + "@vue/reactivity": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.33.tgz", + "integrity": "sha512-62Sq0mp9/0bLmDuxuLD5CIaMG2susFAGARLuZ/5jkU1FCf9EDbwUuF+BO8Ub3Rbodx0ziIecM/NsmyjardBxfQ==", + "requires": { + "@vue/shared": "3.2.33" + } + }, + "@vue/reactivity-transform": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.33.tgz", + "integrity": "sha512-4UL5KOIvSQb254aqenW4q34qMXbfZcmEsV/yVidLUgvwYQQ/D21bGX3DlgPUGI3c4C+iOnNmDCkIxkILoX/Pyw==", + "requires": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.33", + "@vue/shared": "3.2.33", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "@vue/runtime-core": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.33.tgz", + "integrity": "sha512-N2D2vfaXsBPhzCV3JsXQa2NECjxP3eXgZlFqKh4tgakp3iX6LCGv76DLlc+IfFZq+TW10Y8QUfeihXOupJ1dGw==", + "requires": { + "@vue/reactivity": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "@vue/runtime-dom": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.33.tgz", + "integrity": "sha512-LSrJ6W7CZTSUygX5s8aFkraDWlO6K4geOwA3quFF2O+hC3QuAMZt/0Xb7JKE3C4JD4pFwCSO7oCrZmZ0BIJUnw==", + "requires": { + "@vue/runtime-core": "3.2.33", + "@vue/shared": "3.2.33", + "csstype": "^2.6.8" + } + }, + "@vue/server-renderer": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.33.tgz", + "integrity": "sha512-4jpJHRD4ORv8PlbYi+/MfP8ec1okz6rybe36MdpkDrGIdEItHEUyaHSKvz+ptNEyQpALmmVfRteHkU9F8vxOew==", + "requires": { + "@vue/compiler-ssr": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "@vue/shared": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", + "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "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, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "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 + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "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, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "esbuild": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz", + "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.38", + "esbuild-android-arm64": "0.14.38", + "esbuild-darwin-64": "0.14.38", + "esbuild-darwin-arm64": "0.14.38", + "esbuild-freebsd-64": "0.14.38", + "esbuild-freebsd-arm64": "0.14.38", + "esbuild-linux-32": "0.14.38", + "esbuild-linux-64": "0.14.38", + "esbuild-linux-arm": "0.14.38", + "esbuild-linux-arm64": "0.14.38", + "esbuild-linux-mips64le": "0.14.38", + "esbuild-linux-ppc64le": "0.14.38", + "esbuild-linux-riscv64": "0.14.38", + "esbuild-linux-s390x": "0.14.38", + "esbuild-netbsd-64": "0.14.38", + "esbuild-openbsd-64": "0.14.38", + "esbuild-sunos-64": "0.14.38", + "esbuild-windows-32": "0.14.38", + "esbuild-windows-64": "0.14.38", + "esbuild-windows-arm64": "0.14.38" + } + }, + "esbuild-android-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz", + "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz", + "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz", + "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz", + "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz", + "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz", + "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz", + "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz", + "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz", + "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz", + "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz", + "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz", + "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz", + "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz", + "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz", + "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz", + "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz", + "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz", + "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz", + "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.38", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz", + "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==", + "dev": true, + "optional": true + }, + "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 + }, + "eslint": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "requires": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "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, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "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 + }, + "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 + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "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, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "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 + }, + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "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, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "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 + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "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 + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "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 + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "pinia": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.14.tgz", + "integrity": "sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA==", + "requires": { + "@vue/devtools-api": "^6.1.4", + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz", + "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==", + "requires": {} + } + } + }, + "postcss": { + "version": "8.4.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", + "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", + "requires": { + "nanoid": "^3.3.3", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "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 + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.72.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.72.0.tgz", + "integrity": "sha512-KqtR2YcO35/KKijg4nx4STO3569aqCUeGRkKWnJ6r+AvBBrVY9L4pmf4NHVrQr4mTOq6msbohflxr2kpihhaOA==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "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==" + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "three": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", + "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==" + }, + "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, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vite": { + "version": "2.9.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.8.tgz", + "integrity": "sha512-zsBGwn5UT3YS0NLSJ7hnR54+vUKfgzMUh/Z9CxF1YKEBVIe213+63jrFLmZphgGI5zXwQCSmqIdbPuE8NJywPw==", + "dev": true, + "requires": { + "esbuild": "^0.14.27", + "fsevents": "~2.3.2", + "postcss": "^8.4.13", + "resolve": "^1.22.0", + "rollup": "^2.59.0" + } + }, + "vue": { + "version": "3.2.33", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.33.tgz", + "integrity": "sha512-si1ExAlDUrLSIg/V7D/GgA4twJwfsfgG+t9w10z38HhL/HA07132pUQ2KuwAo8qbCyMJ9e6OqrmWrOCr+jW7ZQ==", + "requires": { + "@vue/compiler-dom": "3.2.33", + "@vue/compiler-sfc": "3.2.33", + "@vue/runtime-dom": "3.2.33", + "@vue/server-renderer": "3.2.33", + "@vue/shared": "3.2.33" + } + }, + "vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + } + }, + "vue-router": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.15.tgz", + "integrity": "sha512-xa+pIN9ZqORdIW1MkN2+d9Ui2pCM1b/UMgwYUCZOiFYHAvz/slKKBDha8DLrh5aCG/RibtrpyhKjKOZ85tYyWg==", + "requires": { + "@vue/devtools-api": "^6.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/railsignal-app/package.json b/railsignal-app/package.json new file mode 100644 index 0000000..0e3ecc6 --- /dev/null +++ b/railsignal-app/package.json @@ -0,0 +1,23 @@ +{ + "name": "railsignal-app", + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview --port 5050", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore" + }, + "dependencies": { + "axios": "^0.27.2", + "pinia": "^2.0.14", + "three": "^0.140.0", + "vue": "^3.2.33", + "vue-router": "^4.0.14" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^2.3.1", + "eslint": "^8.5.0", + "eslint-plugin-vue": "^8.2.0", + "vite": "^2.9.5" + } +} diff --git a/railsignal-app/public/favicon.ico b/railsignal-app/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/railsignal-app/public/favicon.ico differ diff --git a/railsignal-app/src/App.vue b/railsignal-app/src/App.vue new file mode 100644 index 0000000..10a2fad --- /dev/null +++ b/railsignal-app/src/App.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/railsignal-app/src/components/RailSystem.vue b/railsignal-app/src/components/RailSystem.vue new file mode 100644 index 0000000..a7d1c7b --- /dev/null +++ b/railsignal-app/src/components/RailSystem.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/railsignal-app/src/components/RailSystemsManager.vue b/railsignal-app/src/components/RailSystemsManager.vue new file mode 100644 index 0000000..568c206 --- /dev/null +++ b/railsignal-app/src/components/RailSystemsManager.vue @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file diff --git a/railsignal-app/src/components/railsystem/AddSegment.vue b/railsignal-app/src/components/railsystem/AddSegment.vue new file mode 100644 index 0000000..9e4f637 --- /dev/null +++ b/railsignal-app/src/components/railsystem/AddSegment.vue @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/railsignal-app/src/components/railsystem/Component.vue b/railsignal-app/src/components/railsystem/Component.vue new file mode 100644 index 0000000..0a4f80e --- /dev/null +++ b/railsignal-app/src/components/railsystem/Component.vue @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/railsignal-app/src/components/railsystem/MapView.vue b/railsignal-app/src/components/railsystem/MapView.vue new file mode 100644 index 0000000..c0c1d0f --- /dev/null +++ b/railsignal-app/src/components/railsystem/MapView.vue @@ -0,0 +1,26 @@ + + + + + \ No newline at end of file diff --git a/railsignal-app/src/main.js b/railsignal-app/src/main.js new file mode 100644 index 0000000..f00dcd1 --- /dev/null +++ b/railsignal-app/src/main.js @@ -0,0 +1,9 @@ +import { createApp } from 'vue'; +import { createPinia } from 'pinia'; +import App from './App.vue' + +const app = createApp(App) +const pinia = createPinia(); +app.use(pinia); + +app.mount('#app') diff --git a/railsignal-app/src/stores/railSystemsStore.js b/railsignal-app/src/stores/railSystemsStore.js new file mode 100644 index 0000000..d9747b1 --- /dev/null +++ b/railsignal-app/src/stores/railSystemsStore.js @@ -0,0 +1,48 @@ +import { defineStore } from "pinia"; +import axios from "axios"; + +export const useRailSystemsStore = defineStore('RailSystemsStore', { + state: () => ({ + railSystems: [], + selectedRailSystem: null, + selectedComponent: null + }), + actions: { + refreshRailSystems() { + return new Promise((resolve, reject) => { + axios.get(import.meta.env.VITE_API_URL + "/rs") + .then(response => { + this.railSystems = response.data; + resolve(); + }) + .catch(error => { + reject(error); + }); + }); + }, + createRailSystem(name) { + return new Promise((resolve, reject) => { + axios.post( + import.meta.env.VITE_API_URL + "/rs", + {name: name} + ) + .then(() => { + this.refreshRailSystems() + .then(() => resolve()) + .catch(error => reject(error)); + }) + .catch(error => reject(error)); + }); + }, + removeRailSystem(rs) { + return new Promise((resolve, reject) => { + axios.delete(import.meta.env.VITE_API_URL + "/rs/" + rs.id) + .then(() => { + this.refreshRailSystems() + .then(() => resolve) + .catch(error => reject(error)); + }) + }) + } + } +}); \ No newline at end of file diff --git a/railsignal-app/vite.config.js b/railsignal-app/vite.config.js new file mode 100644 index 0000000..116273f --- /dev/null +++ b/railsignal-app/vite.config.js @@ -0,0 +1,14 @@ +import { fileURLToPath, URL } from 'url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/src/main/java/nl/andrewl/railsignalapi/dao/ComponentRepository.java b/src/main/java/nl/andrewl/railsignalapi/dao/ComponentRepository.java index 3e5e0c9..862c122 100644 --- a/src/main/java/nl/andrewl/railsignalapi/dao/ComponentRepository.java +++ b/src/main/java/nl/andrewl/railsignalapi/dao/ComponentRepository.java @@ -2,10 +2,27 @@ package nl.andrewl.railsignalapi.dao; import nl.andrewl.railsignalapi.model.RailSystem; import nl.andrewl.railsignalapi.model.component.Component; +import nl.andrewl.railsignalapi.model.component.Position; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository -public interface ComponentRepository extends JpaRepository { +public interface ComponentRepository extends JpaRepository { + Optional findByIdAndRailSystemId(long id, long rsId); + + boolean existsByNameAndRailSystem(String name, RailSystem rs); + + @Query("SELECT c FROM Component c " + + "WHERE c.railSystem = :rs AND " + + "c.position.x >= :#{#lower.x} AND c.position.y >= :#{#lower.y} AND c.position.z >= :#{#lower.z} AND " + + "c.position.x <= :#{#upper.x} AND c.position.y <= :#{#upper.y} AND c.position.z <= :#{#upper.z}") + List findAllInBounds(RailSystem rs, Position lower, Position upper); + + List findAllByRailSystem(RailSystem rs); + void deleteAllByRailSystem(RailSystem rs); } diff --git a/src/main/java/nl/andrewl/railsignalapi/dao/SegmentRepository.java b/src/main/java/nl/andrewl/railsignalapi/dao/SegmentRepository.java index 3cde24a..ebba876 100644 --- a/src/main/java/nl/andrewl/railsignalapi/dao/SegmentRepository.java +++ b/src/main/java/nl/andrewl/railsignalapi/dao/SegmentRepository.java @@ -5,7 +5,16 @@ import nl.andrewl.railsignalapi.model.Segment; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface SegmentRepository extends JpaRepository { + boolean existsByNameAndRailSystem(String name, RailSystem rs); + + List findAllByRailSystemId(long rsId); + + Optional findByIdAndRailSystemId(long id, long rsId); + void deleteAllByRailSystem(RailSystem rs); } diff --git a/src/main/java/nl/andrewl/railsignalapi/dao/SignalRepository.java b/src/main/java/nl/andrewl/railsignalapi/dao/SignalRepository.java new file mode 100644 index 0000000..0bea913 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/dao/SignalRepository.java @@ -0,0 +1,8 @@ +package nl.andrewl.railsignalapi.dao; + +import nl.andrewl.railsignalapi.model.component.Signal; +import org.springframework.stereotype.Repository; + +@Repository +public interface SignalRepository extends ComponentRepository { +} diff --git a/src/main/java/nl/andrewl/railsignalapi/dao/SwitchConfigurationRepository.java b/src/main/java/nl/andrewl/railsignalapi/dao/SwitchConfigurationRepository.java new file mode 100644 index 0000000..5c5e52f --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/dao/SwitchConfigurationRepository.java @@ -0,0 +1,11 @@ +package nl.andrewl.railsignalapi.dao; + +import nl.andrewl.railsignalapi.model.component.PathNode; +import nl.andrewl.railsignalapi.model.component.SwitchConfiguration; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SwitchConfigurationRepository extends JpaRepository { + void deleteAllByNodesContaining(PathNode p); +} diff --git a/src/main/java/nl/andrewl/railsignalapi/dao/SwitchRepository.java b/src/main/java/nl/andrewl/railsignalapi/dao/SwitchRepository.java new file mode 100644 index 0000000..2738d8d --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/dao/SwitchRepository.java @@ -0,0 +1,8 @@ +package nl.andrewl.railsignalapi.dao; + +import nl.andrewl.railsignalapi.model.component.Switch; +import org.springframework.stereotype.Repository; + +@Repository +public interface SwitchRepository extends ComponentRepository { +} diff --git a/src/main/java/nl/andrewl/railsignalapi/model/Segment.java b/src/main/java/nl/andrewl/railsignalapi/model/Segment.java index efe0b8f..f05b9cf 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/Segment.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/Segment.java @@ -7,6 +7,7 @@ import nl.andrewl.railsignalapi.model.component.SegmentBoundaryNode; import nl.andrewl.railsignalapi.model.component.Signal; import javax.persistence.*; +import java.util.HashSet; import java.util.Set; /** @@ -27,7 +28,7 @@ public class Segment { /** * A unique name for this segment. */ - @Column(unique = true) + @Column private String name; /** @@ -39,9 +40,16 @@ public class Segment { /** * The set of nodes from which trains can enter and exit this segment. */ - @ManyToMany(mappedBy = "segments", cascade = CascadeType.ALL) + @ManyToMany(mappedBy = "segments") private Set boundaryNodes; + public Segment(RailSystem railSystem, String name) { + this.railSystem = railSystem; + this.name = name; + this.signals = new HashSet<>(); + this.boundaryNodes = new HashSet<>(); + } + @Override public boolean equals(Object o) { if (o == this) return true; diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/Component.java b/src/main/java/nl/andrewl/railsignalapi/model/component/Component.java index a0ff76c..3bbe652 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/Component.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/Component.java @@ -37,9 +37,15 @@ public abstract class Component { /** * A human-readable name for the component. */ - @Column(unique = true) + @Column private String name; + /** + * The type of this component. + */ + @Enumerated(EnumType.ORDINAL) + private ComponentType type; + /** * Whether this component is online, meaning that an in-world device is * currently connected to relay information regarding this component. @@ -48,10 +54,11 @@ public abstract class Component { @Setter private boolean online = false; - public Component(RailSystem railSystem, Position position, String name) { + public Component(RailSystem railSystem, Position position, String name, ComponentType type) { this.railSystem = railSystem; this.position = position; this.name = name; + this.type = type; } @Override @@ -59,4 +66,13 @@ public abstract class Component { if (this == o) return true; return o instanceof Component c && this.id != null && this.id.equals(c.id); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(id); + if (name != null) sb.append('[').append(name).append(']'); + sb.append(String.format("@[x=%.1f,y=%.1f,z=%.1f]", position.getX(), position.getY(), position.getZ())); + return sb.toString(); + } } diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/ComponentType.java b/src/main/java/nl/andrewl/railsignalapi/model/component/ComponentType.java new file mode 100644 index 0000000..af9baeb --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/ComponentType.java @@ -0,0 +1,7 @@ +package nl.andrewl.railsignalapi.model.component; + +public enum ComponentType { + SIGNAL, + SWITCH, + SEGMENT_BOUNDARY +} diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/PathNode.java b/src/main/java/nl/andrewl/railsignalapi/model/component/PathNode.java index 6d82422..975e9bf 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/PathNode.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/PathNode.java @@ -19,15 +19,15 @@ import java.util.Set; @Inheritance(strategy = InheritanceType.JOINED) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -public class PathNode extends Component { +public abstract class PathNode extends Component { /** * The set of nodes that this one is connected to. */ @ManyToMany private Set connectedNodes; - public PathNode(RailSystem railSystem, Position position, String name, Set connectedNodes) { - super(railSystem, position, name); + public PathNode(RailSystem railSystem, Position position, String name, ComponentType type, Set connectedNodes) { + super(railSystem, position, name, type); this.connectedNodes = connectedNodes; } } diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/SegmentBoundaryNode.java b/src/main/java/nl/andrewl/railsignalapi/model/component/SegmentBoundaryNode.java index 0b9923d..969e727 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/SegmentBoundaryNode.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/SegmentBoundaryNode.java @@ -26,7 +26,7 @@ public class SegmentBoundaryNode extends PathNode { private Set segments; public SegmentBoundaryNode(RailSystem railSystem, Position position, String name, Set connectedNodes, Set segments) { - super(railSystem, position, name, connectedNodes); + super(railSystem, position, name, ComponentType.SEGMENT_BOUNDARY, connectedNodes); this.segments = segments; } } diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/Signal.java b/src/main/java/nl/andrewl/railsignalapi/model/component/Signal.java index 591542d..2e1446f 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/Signal.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/Signal.java @@ -1,12 +1,14 @@ package nl.andrewl.railsignalapi.model.component; import lombok.AccessLevel; +import lombok.Getter; import lombok.NoArgsConstructor; -import nl.andrewl.railsignalapi.model.Direction; import nl.andrewl.railsignalapi.model.RailSystem; import nl.andrewl.railsignalapi.model.Segment; -import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; /** * A signal is a component that relays the status of a connected segment to @@ -15,29 +17,16 @@ import javax.persistence.*; */ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter public class Signal extends Component { - /** - * The direction this signal is facing. This is the direction in which the - * signal connects to a branch. - *
-	 *     |-segment A-|-segment B-|
-	 *     ===================== <- Rail
-	 *                ]+  --->      Signal is facing East, and shows status on
-	 *                              its western side. It is connected to segment B.
-	 * 
- */ - @Enumerated(EnumType.STRING) - private Direction direction; - /** * The segment that this signal connects to. */ @ManyToOne(optional = false, fetch = FetchType.LAZY) private Segment segment; - public Signal(RailSystem railSystem, Position position, String name, Segment segment, Direction direction) { - super(railSystem, position, name); + public Signal(RailSystem railSystem, Position position, String name, Segment segment) { + super(railSystem, position, name, ComponentType.SIGNAL); this.segment = segment; - this.direction = direction; } } diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/Switch.java b/src/main/java/nl/andrewl/railsignalapi/model/component/Switch.java index afa8c80..ce3b1e9 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/Switch.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/Switch.java @@ -3,6 +3,8 @@ package nl.andrewl.railsignalapi.model.component; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.andrewl.railsignalapi.model.RailSystem; import javax.persistence.*; import java.util.Set; @@ -22,8 +24,16 @@ public class Switch extends PathNode { private Set possibleConfigurations; /** - * The switch configuration that this switch is currently in. + * The switch configuration that this switch is currently in. If null, then + * we don't know what configuration the switch is in. */ - @OneToOne(optional = false, fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY) + @Setter private SwitchConfiguration activeConfiguration; + + public Switch(RailSystem railSystem, Position position, String name, Set connectedNodes, Set possibleConfigurations, SwitchConfiguration activeConfiguration) { + super(railSystem, position, name, ComponentType.SWITCH, connectedNodes); + this.possibleConfigurations = possibleConfigurations; + this.activeConfiguration = activeConfiguration; + } } diff --git a/src/main/java/nl/andrewl/railsignalapi/model/component/SwitchConfiguration.java b/src/main/java/nl/andrewl/railsignalapi/model/component/SwitchConfiguration.java index 261f81c..b6a4f23 100644 --- a/src/main/java/nl/andrewl/railsignalapi/model/component/SwitchConfiguration.java +++ b/src/main/java/nl/andrewl/railsignalapi/model/component/SwitchConfiguration.java @@ -1,5 +1,7 @@ package nl.andrewl.railsignalapi.model.component; +import lombok.AccessLevel; +import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.*; @@ -10,7 +12,8 @@ import java.util.Set; * as an active configuration in the linked switch component. */ @Entity -@NoArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter public class SwitchConfiguration { @Id @GeneratedValue @@ -28,4 +31,17 @@ public class SwitchConfiguration { */ @ManyToMany(fetch = FetchType.EAGER) private Set nodes; + + public SwitchConfiguration(Switch switchComponent, Set nodes) { + this.switchComponent = switchComponent; + this.nodes = nodes; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + return o instanceof SwitchConfiguration sc && + sc.switchComponent.equals(this.switchComponent) && + sc.nodes.equals(this.nodes); + } } diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/ComponentsApiController.java b/src/main/java/nl/andrewl/railsignalapi/rest/ComponentsApiController.java new file mode 100644 index 0000000..1a83b3c --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/ComponentsApiController.java @@ -0,0 +1,39 @@ +package nl.andrewl.railsignalapi.rest; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.RequiredArgsConstructor; +import nl.andrewl.railsignalapi.rest.dto.component.ComponentResponse; +import nl.andrewl.railsignalapi.rest.dto.component.SimpleComponentResponse; +import nl.andrewl.railsignalapi.service.ComponentService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping(path = "/api/rs/{rsId}/c") +@RequiredArgsConstructor +public class ComponentsApiController { + private final ComponentService componentService; + + @GetMapping + public List getAllComponents(@PathVariable long rsId) { + return componentService.getComponents(rsId); + } + + @GetMapping(path = "/{cId}") + public ComponentResponse getComponent(@PathVariable long rsId, @PathVariable long cId) { + return componentService.getComponent(rsId, cId); + } + + @PostMapping + public ComponentResponse createComponent(@PathVariable long rsId, @RequestBody ObjectNode data) { + return componentService.create(rsId, data); + } + + @DeleteMapping(path = "/{cId}") + public ResponseEntity removeComponent(@PathVariable long rsId, @PathVariable long cId) { + componentService.removeComponent(rsId, cId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/SegmentPayload.java b/src/main/java/nl/andrewl/railsignalapi/rest/SegmentPayload.java new file mode 100644 index 0000000..9bda7f6 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/SegmentPayload.java @@ -0,0 +1,4 @@ +package nl.andrewl.railsignalapi.rest; + +public record SegmentPayload(String name) { +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/SegmentsApiController.java b/src/main/java/nl/andrewl/railsignalapi/rest/SegmentsApiController.java new file mode 100644 index 0000000..80418a1 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/SegmentsApiController.java @@ -0,0 +1,31 @@ +package nl.andrewl.railsignalapi.rest; + +import lombok.RequiredArgsConstructor; +import nl.andrewl.railsignalapi.rest.dto.FullSegmentResponse; +import nl.andrewl.railsignalapi.rest.dto.SegmentResponse; +import nl.andrewl.railsignalapi.service.SegmentService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping(path = "/api/rs/{rsId}/s") +@RequiredArgsConstructor +public class SegmentsApiController { + private final SegmentService segmentService; + + @GetMapping + public List getSegments(@PathVariable long rsId) { + return segmentService.getSegments(rsId); + } + + @GetMapping(path = "/{sId}") + public FullSegmentResponse getSegment(@PathVariable long rsId, @PathVariable long sId) { + return segmentService.getSegment(rsId, sId); + } + + @PostMapping + public FullSegmentResponse createSegment(@PathVariable long rsId, @RequestBody SegmentPayload payload) { + return segmentService.create(rsId, payload); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/WebConfig.java b/src/main/java/nl/andrewl/railsignalapi/rest/WebConfig.java index 1be14a6..22a3e05 100644 --- a/src/main/java/nl/andrewl/railsignalapi/rest/WebConfig.java +++ b/src/main/java/nl/andrewl/railsignalapi/rest/WebConfig.java @@ -1,6 +1,7 @@ package nl.andrewl.railsignalapi.rest; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -13,4 +14,13 @@ public class WebConfig implements WebMvcConfigurer { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("*"); + } + + } diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/FullSegmentResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/FullSegmentResponse.java new file mode 100644 index 0000000..ae8cbde --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/FullSegmentResponse.java @@ -0,0 +1,18 @@ +package nl.andrewl.railsignalapi.rest.dto; + +import nl.andrewl.railsignalapi.model.Segment; +import nl.andrewl.railsignalapi.rest.dto.component.SegmentBoundaryNodeResponse; +import nl.andrewl.railsignalapi.rest.dto.component.SignalResponse; + +import java.util.List; + +public class FullSegmentResponse extends SegmentResponse { + public List signals; + public List boundaryNodes; + + public FullSegmentResponse(Segment s) { + super(s); + this.signals = s.getSignals().stream().map(SignalResponse::new).toList(); + this.boundaryNodes = s.getBoundaryNodes().stream().map(SegmentBoundaryNodeResponse::new).toList(); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/SegmentResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/SegmentResponse.java new file mode 100644 index 0000000..617774b --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/SegmentResponse.java @@ -0,0 +1,17 @@ +package nl.andrewl.railsignalapi.rest.dto; + +import nl.andrewl.railsignalapi.model.Segment; + +public class SegmentResponse { + public long id; + public String name; + + public SegmentResponse(long id, String name) { + this.id = id; + this.name = name; + } + + public SegmentResponse(Segment s) { + this(s.getId(), s.getName()); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/ComponentResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/ComponentResponse.java new file mode 100644 index 0000000..7fd74f7 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/ComponentResponse.java @@ -0,0 +1,27 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.*; + +public abstract class ComponentResponse { + public long id; + public Position position; + public String name; + public String type; + public boolean online; + + public ComponentResponse(Component c) { + this.id = c.getId(); + this.position = c.getPosition(); + this.name = c.getName(); + this.type = c.getType().name(); + this.online = c.isOnline(); + } + + public static ComponentResponse of(Component c) { + return switch (c.getType()) { + case SIGNAL -> new SignalResponse((Signal) c); + case SWITCH -> new SwitchResponse((Switch) c); + case SEGMENT_BOUNDARY -> new SegmentBoundaryNodeResponse((SegmentBoundaryNode) c); + }; + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/PathNodeResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/PathNodeResponse.java new file mode 100644 index 0000000..1c83196 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/PathNodeResponse.java @@ -0,0 +1,14 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.PathNode; + +import java.util.List; + +public abstract class PathNodeResponse extends ComponentResponse { + public List connectedNodes; + + public PathNodeResponse(PathNode p) { + super(p); + this.connectedNodes = p.getConnectedNodes().stream().map(SimpleComponentResponse::new).toList(); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SegmentBoundaryNodeResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SegmentBoundaryNodeResponse.java new file mode 100644 index 0000000..ba09712 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SegmentBoundaryNodeResponse.java @@ -0,0 +1,15 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.SegmentBoundaryNode; +import nl.andrewl.railsignalapi.rest.dto.SegmentResponse; + +import java.util.List; + +public class SegmentBoundaryNodeResponse extends PathNodeResponse { + public List segments; + + public SegmentBoundaryNodeResponse(SegmentBoundaryNode n) { + super(n); + this.segments = n.getSegments().stream().map(SegmentResponse::new).toList(); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SignalResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SignalResponse.java new file mode 100644 index 0000000..56dd8d5 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SignalResponse.java @@ -0,0 +1,12 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.Signal; +import nl.andrewl.railsignalapi.rest.dto.SegmentResponse; + +public class SignalResponse extends ComponentResponse { + public SegmentResponse segment; + public SignalResponse(Signal s) { + super(s); + this.segment = new SegmentResponse(s.getSegment()); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SimpleComponentResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SimpleComponentResponse.java new file mode 100644 index 0000000..6b6a9da --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SimpleComponentResponse.java @@ -0,0 +1,22 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.Component; +import nl.andrewl.railsignalapi.model.component.Position; + +public record SimpleComponentResponse ( + long id, + Position position, + String name, + String type, + boolean online +) { + public SimpleComponentResponse(Component c) { + this( + c.getId(), + c.getPosition(), + c.getName(), + c.getType().name(), + c.isOnline() + ); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchConfigurationResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchConfigurationResponse.java new file mode 100644 index 0000000..f65a5b6 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchConfigurationResponse.java @@ -0,0 +1,17 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.SwitchConfiguration; + +import java.util.List; + +public record SwitchConfigurationResponse ( + long id, + List nodes +) { + public SwitchConfigurationResponse(SwitchConfiguration sc) { + this( + sc.getId(), + sc.getNodes().stream().map(SimpleComponentResponse::new).toList() + ); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchResponse.java b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchResponse.java new file mode 100644 index 0000000..b854bc0 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/rest/dto/component/SwitchResponse.java @@ -0,0 +1,16 @@ +package nl.andrewl.railsignalapi.rest.dto.component; + +import nl.andrewl.railsignalapi.model.component.Switch; + +import java.util.List; + +public class SwitchResponse extends PathNodeResponse { + public List possibleConfigurations; + public SwitchConfigurationResponse activeConfiguration; + + public SwitchResponse(Switch s) { + super(s); + this.possibleConfigurations = s.getPossibleConfigurations().stream().map(SwitchConfigurationResponse::new).toList(); + this.activeConfiguration = new SwitchConfigurationResponse(s.getActiveConfiguration()); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/service/BranchService.java b/src/main/java/nl/andrewl/railsignalapi/service/BranchService.java deleted file mode 100644 index 3a3dc08..0000000 --- a/src/main/java/nl/andrewl/railsignalapi/service/BranchService.java +++ /dev/null @@ -1,57 +0,0 @@ -package nl.andrewl.railsignalapi.service; - -import lombok.RequiredArgsConstructor; -import nl.andrewl.railsignalapi.dao.BranchRepository; -import nl.andrewl.railsignalapi.dao.RailSystemRepository; -import nl.andrewl.railsignalapi.dao.SignalRepository; -import nl.andrewl.railsignalapi.rest.dto.BranchResponse; -import nl.andrewl.railsignalapi.rest.dto.SignalResponse; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.server.ResponseStatusException; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class BranchService { - private final BranchRepository branchRepository; - private final RailSystemRepository railSystemRepository; - private final SignalRepository signalRepository; - - @Transactional - public void deleteBranch(long rsId, long branchId) { - var branch = branchRepository.findByIdAndRailSystemId(branchId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - if (!branch.getSignalConnections().isEmpty()) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Branch should not be connected to any signals."); - } - branchRepository.delete(branch); - } - - @Transactional(readOnly = true) - public List getAllBranches(long rsId) { - var rs = railSystemRepository.findById(rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - return branchRepository.findAllByRailSystemOrderByName(rs).stream() - .map(BranchResponse::new) - .toList(); - } - - @Transactional(readOnly = true) - public BranchResponse getBranch(long rsId, long branchId) { - var branch = branchRepository.findByIdAndRailSystemId(branchId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - return new BranchResponse(branch); - } - - @Transactional(readOnly = true) - public List getConnectedSignals(long rsId, long branchId) { - var branch = branchRepository.findByIdAndRailSystemId(branchId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - return signalRepository.findAllConnectedToBranch(branch).stream() - .map(SignalResponse::new) - .toList(); - } -} diff --git a/src/main/java/nl/andrewl/railsignalapi/service/ComponentService.java b/src/main/java/nl/andrewl/railsignalapi/service/ComponentService.java new file mode 100644 index 0000000..c39803c --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/service/ComponentService.java @@ -0,0 +1,129 @@ +package nl.andrewl.railsignalapi.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.RequiredArgsConstructor; +import nl.andrewl.railsignalapi.dao.ComponentRepository; +import nl.andrewl.railsignalapi.dao.RailSystemRepository; +import nl.andrewl.railsignalapi.dao.SegmentRepository; +import nl.andrewl.railsignalapi.dao.SwitchConfigurationRepository; +import nl.andrewl.railsignalapi.model.RailSystem; +import nl.andrewl.railsignalapi.model.Segment; +import nl.andrewl.railsignalapi.model.component.*; +import nl.andrewl.railsignalapi.rest.dto.component.ComponentResponse; +import nl.andrewl.railsignalapi.rest.dto.component.SimpleComponentResponse; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class ComponentService { + private final ComponentRepository componentRepository; + private final RailSystemRepository railSystemRepository; + private final SegmentRepository segmentRepository; + private final SwitchConfigurationRepository switchConfigurationRepository; + + @Transactional(readOnly = true) + public List getComponents(long rsId) { + var rs = railSystemRepository.findById(rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + return componentRepository.findAllByRailSystem(rs).stream().map(SimpleComponentResponse::new).toList(); + } + + @Transactional(readOnly = true) + public ComponentResponse getComponent(long rsId, long componentId) { + var c = componentRepository.findByIdAndRailSystemId(componentId, rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + return ComponentResponse.of(c); + } + + @Transactional + public void removeComponent(long rsId, long componentId) { + var c = componentRepository.findByIdAndRailSystemId(componentId, rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + // If this is a path node, check for and remove any switch configurations that use it. + if (c instanceof PathNode p) { + switchConfigurationRepository.deleteAllByNodesContaining(p); + } + componentRepository.delete(c); + } + + @Transactional + public ComponentResponse create(long rsId, ObjectNode data) { + RailSystem rs = railSystemRepository.findById(rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + String type = data.get("type").asText(); + Position pos = new Position(); + pos.setX(data.get("position").get("x").asDouble()); + pos.setY(data.get("position").get("y").asDouble()); + pos.setZ(data.get("position").get("z").asDouble()); + String name = data.get("name").asText(); + + if (name != null && componentRepository.existsByNameAndRailSystem(name, rs)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Component with that name already exists."); + } + + Component c = switch (type) { + case "SIGNAL" -> createSignal(rs, pos, name, data); + case "SWITCH" -> createSwitch(rs, pos, name, data); + case "SEGMENT_BOUNDARY" -> createSegmentBoundary(rs, pos, name, data); + default -> throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported component type: " + type); + }; + c = componentRepository.save(c); + return ComponentResponse.of(c); + } + + private Component createSignal(RailSystem rs, Position pos, String name, ObjectNode data) { + long segmentId = data.get("segment").get("id").asLong(); + Segment segment = segmentRepository.findById(segmentId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + return new Signal(rs, pos, name, segment); + } + + private Component createSwitch(RailSystem rs, Position pos, String name, ObjectNode data) { + Switch s = new Switch(rs, pos, name, new HashSet<>(), new HashSet<>(), null); + for (JsonNode configJson : data.withArray("possibleConfigurations")) { + Set pathNodes = new HashSet<>(); + for (JsonNode pathNodeJson : configJson.withArray("nodes")) { + long pathNodeId = pathNodeJson.get("id").asLong(); + Component c = componentRepository.findById(pathNodeId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + if (c instanceof PathNode pathNode) { + pathNodes.add(pathNode); + s.getConnectedNodes().add(pathNode); + } else { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Id " + pathNodeId + " does not refer to a PathNode component."); + } + } + s.getPossibleConfigurations().add(new SwitchConfiguration(s, pathNodes)); + } + return s; + } + + private Component createSegmentBoundary(RailSystem rs, Position pos, String name, ObjectNode data) { + ArrayNode segmentsNode = data.withArray("segments"); + Set segments = new HashSet<>(); + for (JsonNode segmentNode : segmentsNode) { + long segmentId = segmentNode.get("id").asLong(); + Segment segment = segmentRepository.findById(segmentId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + segments.add(segment); + } + if (segments.size() < 1 || segments.size() > 2) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid number of segments."); + } + return new SegmentBoundaryNode(rs, pos, name, new HashSet<>(), segments); + } + + @Transactional + public void remove(long rsId, long componentId) { + + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/service/RailSystemService.java b/src/main/java/nl/andrewl/railsignalapi/service/RailSystemService.java index 2e9e1f1..b5d7267 100644 --- a/src/main/java/nl/andrewl/railsignalapi/service/RailSystemService.java +++ b/src/main/java/nl/andrewl/railsignalapi/service/RailSystemService.java @@ -20,7 +20,7 @@ import java.util.List; public class RailSystemService { private final RailSystemRepository railSystemRepository; private final SegmentRepository segmentRepository; - private final ComponentRepository componentRepository; + private final ComponentRepository componentRepository; @Transactional public List getRailSystems() { @@ -29,10 +29,13 @@ public class RailSystemService { @Transactional public RailSystemResponse createRailSystem(RailSystemCreationPayload payload) { - if (railSystemRepository.existsByName(payload.name())) { + if (payload.name() == null) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Missing required name."); + if (payload.name().isBlank()) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Name cannot be blank."); + String name = payload.name().trim(); + if (railSystemRepository.existsByName(name)) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "A rail system with that name already exists."); } - RailSystem rs = new RailSystem(payload.name()); + RailSystem rs = new RailSystem(name); return new RailSystemResponse(railSystemRepository.save(rs)); } diff --git a/src/main/java/nl/andrewl/railsignalapi/service/SegmentService.java b/src/main/java/nl/andrewl/railsignalapi/service/SegmentService.java new file mode 100644 index 0000000..3b7dfe7 --- /dev/null +++ b/src/main/java/nl/andrewl/railsignalapi/service/SegmentService.java @@ -0,0 +1,57 @@ +package nl.andrewl.railsignalapi.service; + +import lombok.RequiredArgsConstructor; +import nl.andrewl.railsignalapi.dao.ComponentRepository; +import nl.andrewl.railsignalapi.dao.RailSystemRepository; +import nl.andrewl.railsignalapi.dao.SegmentRepository; +import nl.andrewl.railsignalapi.model.Segment; +import nl.andrewl.railsignalapi.model.component.Component; +import nl.andrewl.railsignalapi.rest.SegmentPayload; +import nl.andrewl.railsignalapi.rest.dto.FullSegmentResponse; +import nl.andrewl.railsignalapi.rest.dto.SegmentResponse; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class SegmentService { + private final SegmentRepository segmentRepository; + private final RailSystemRepository railSystemRepository; + private final ComponentRepository componentRepository; + + @Transactional(readOnly = true) + public List getSegments(long rsId) { + return segmentRepository.findAllByRailSystemId(rsId).stream().map(SegmentResponse::new).toList(); + } + + @Transactional(readOnly = true) + public FullSegmentResponse getSegment(long rsId, long segmentId) { + var segment = segmentRepository.findByIdAndRailSystemId(segmentId, rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + return new FullSegmentResponse(segment); + } + + @Transactional + public FullSegmentResponse create(long rsId, SegmentPayload payload) { + var rs = railSystemRepository.findById(rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + String name = payload.name(); + if (segmentRepository.existsByNameAndRailSystem(name, rs)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Segment with that name already exists."); + } + Segment segment = segmentRepository.save(new Segment(rs, name)); + return new FullSegmentResponse(segment); + } + + @Transactional + public void remove(long rsId, long segmentId) { + var segment = segmentRepository.findByIdAndRailSystemId(segmentId, rsId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + componentRepository.deleteAll(segment.getSignals()); + componentRepository.deleteAll(segment.getBoundaryNodes()); + } +} diff --git a/src/main/java/nl/andrewl/railsignalapi/service/SignalService.java b/src/main/java/nl/andrewl/railsignalapi/service/SignalService.java deleted file mode 100644 index 570bae2..0000000 --- a/src/main/java/nl/andrewl/railsignalapi/service/SignalService.java +++ /dev/null @@ -1,246 +0,0 @@ -package nl.andrewl.railsignalapi.service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import nl.andrewl.railsignalapi.dao.BranchRepository; -import nl.andrewl.railsignalapi.dao.RailSystemRepository; -import nl.andrewl.railsignalapi.dao.SignalBranchConnectionRepository; -import nl.andrewl.railsignalapi.dao.SignalRepository; -import nl.andrewl.railsignalapi.model.*; -import nl.andrewl.railsignalapi.model.component.SignalBranchConnection; -import nl.andrewl.railsignalapi.rest.dto.SignalConnectionsUpdatePayload; -import nl.andrewl.railsignalapi.rest.dto.SignalCreationPayload; -import nl.andrewl.railsignalapi.rest.dto.SignalResponse; -import nl.andrewl.railsignalapi.websocket.BranchUpdateMessage; -import nl.andrewl.railsignalapi.websocket.SignalUpdateMessage; -import nl.andrewl.railsignalapi.websocket.SignalUpdateType; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.server.ResponseStatusException; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketMessage; -import org.springframework.web.socket.WebSocketSession; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -@Service -@RequiredArgsConstructor -@Slf4j -public class SignalService { - private final RailSystemRepository railSystemRepository; - private final SignalRepository signalRepository; - private final BranchRepository branchRepository; - private final SignalBranchConnectionRepository signalBranchConnectionRepository; - - private final ObjectMapper mapper = new ObjectMapper(); - private final Map> signalWebSocketSessions = new ConcurrentHashMap<>(); - - @Transactional - public SignalResponse createSignal(long rsId, SignalCreationPayload payload) { - var rs = railSystemRepository.findById(rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Rail system not found.")); - if (signalRepository.existsByNameAndRailSystem(payload.name(), rs)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Signal " + payload.name() + " already exists."); - } - if (payload.branchConnections().size() != 2) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Exactly two branch connections must be provided."); - } - // Ensure that the directions of the connections are opposite each other. - Direction dir1 = Direction.parse(payload.branchConnections().get(0).direction()); - Direction dir2 = Direction.parse(payload.branchConnections().get(1).direction()); - if (!dir1.isOpposite(dir2)) throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Branch connections must be opposite each other."); - - Set branchConnections = new HashSet<>(); - Signal signal = new Signal(rs, payload.name(), payload.position(), branchConnections); - for (var branchData : payload.branchConnections()) { - Branch branch; - if (branchData.id() != null) { - branch = this.branchRepository.findByIdAndRailSystem(branchData.id(), rs) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Branch id " + branchData.id() + " is invalid.")); - } else { - branch = this.branchRepository.findByNameAndRailSystem(branchData.name(), rs) - .orElse(new Branch(rs, branchData.name(), BranchStatus.FREE)); - } - Direction dir = Direction.parse(branchData.direction()); - branchConnections.add(new SignalBranchConnection(signal, branch, dir)); - } - signal = signalRepository.save(signal); - return new SignalResponse(signal); - } - - @Transactional - public SignalResponse updateSignalBranchConnections(long rsId, long sigId, SignalConnectionsUpdatePayload payload) { - var signal = signalRepository.findByIdAndRailSystemId(sigId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - for (var c : payload.connections()) { - var fromConnection = signalBranchConnectionRepository.findById(c.from()) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not find signal branch connection: " + c.from())); - if (!fromConnection.getSignal().getId().equals(signal.getId())) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Can only update signal branch connections originating from the specified signal."); - } - var toConnection = signalBranchConnectionRepository.findById(c.to()) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not find signal branch connection: " + c.to())); - if (!fromConnection.getBranch().getId().equals(toConnection.getBranch().getId())) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Signal branch connections can only path via a mutual branch."); - } - fromConnection.getReachableSignalConnections().add(toConnection); - signalBranchConnectionRepository.save(fromConnection); - } - for (var con : signal.getBranchConnections()) { - Set connectionsToRemove = new HashSet<>(); - for (var reachableCon : con.getReachableSignalConnections()) { - if (!payload.connections().contains(new SignalConnectionsUpdatePayload.ConnectionData(con.getId(), reachableCon.getId()))) { - connectionsToRemove.add(reachableCon); - } - } - con.getReachableSignalConnections().removeAll(connectionsToRemove); - signalBranchConnectionRepository.save(con); - } - // Reload the signal. - signal = signalRepository.findById(signal.getId()).orElseThrow(); - return new SignalResponse(signal); - } - - @Transactional - public void registerSignalWebSocketSession(Set signalIds, WebSocketSession session) { - this.signalWebSocketSessions.put(session, signalIds); - // Instantly send a data packet so that the signals are up-to-date. - RailSystem rs = null; - for (var signalId : signalIds) { - var signal = signalRepository.findById(signalId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid signal id.")); - if (rs == null) { - rs = signal.getRailSystem(); - } else if (!rs.getId().equals(signal.getRailSystem().getId())) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot open signal websocket session for signals from different rail systems."); - } - for (var branchConnection : signal.getBranchConnections()) { - try { - session.sendMessage(new TextMessage(mapper.writeValueAsString( - new BranchUpdateMessage( - branchConnection.getBranch().getId(), - branchConnection.getBranch().getStatus().name() - ) - ))); - } catch (IOException e) { - e.printStackTrace(); - } - } - signal.setOnline(true); - signalRepository.save(signal); - } - } - - @Transactional - public void deregisterSignalWebSocketSession(WebSocketSession session) { - var ids = this.signalWebSocketSessions.remove(session); - if (ids != null) { - for (var signalId : ids) { - signalRepository.findById(signalId).ifPresent(signal -> { - signal.setOnline(false); - signalRepository.save(signal); - }); - } - } - } - - public WebSocketSession getSignalWebSocketSession(long signalId) { - for (var entry : signalWebSocketSessions.entrySet()) { - if (entry.getValue().contains(signalId)) return entry.getKey(); - } - return null; - } - - @Transactional - public void handleSignalUpdate(SignalUpdateMessage updateMessage) { - var signal = signalRepository.findById(updateMessage.signalId()) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - Branch fromBranch = null; - Branch toBranch = null; - for (var con : signal.getBranchConnections()) { - if (con.getBranch().getId() == updateMessage.fromBranchId()) { - fromBranch = con.getBranch(); - } - if (con.getBranch().getId() == updateMessage.toBranchId()) { - toBranch = con.getBranch(); - } - } - if (fromBranch == null || toBranch == null) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid branches."); - } - SignalUpdateType updateType = SignalUpdateType.valueOf(updateMessage.type().trim().toUpperCase()); - if (updateType == SignalUpdateType.BEGIN && toBranch.getStatus() != BranchStatus.FREE) { - log.warn("Warning! Train is entering a non-free branch {}.", toBranch.getName()); - } - if (toBranch.getStatus() != BranchStatus.OCCUPIED) { - log.info("Updating branch {} status from {} to {}.", toBranch.getName(), toBranch.getStatus(), BranchStatus.OCCUPIED); - toBranch.setStatus(BranchStatus.OCCUPIED); - branchRepository.save(toBranch); - broadcastToConnectedSignals(toBranch); - } - if (updateType == SignalUpdateType.END) { - if (fromBranch.getStatus() != BranchStatus.FREE) { - log.info("Updating branch {} status from {} to {}.", fromBranch.getName(), fromBranch.getStatus(), BranchStatus.FREE); - fromBranch.setStatus(BranchStatus.FREE); - branchRepository.save(fromBranch); - broadcastToConnectedSignals(fromBranch); - } - } else if (updateType == SignalUpdateType.BEGIN) { - if (fromBranch.getStatus() != BranchStatus.OCCUPIED) { - log.info("Updating branch {} status from {} to {}.", fromBranch.getName(), fromBranch.getStatus(), BranchStatus.OCCUPIED); - fromBranch.setStatus(BranchStatus.OCCUPIED); - branchRepository.save(fromBranch); - broadcastToConnectedSignals(fromBranch); - } - } - } - - private void broadcastToConnectedSignals(Branch branch) { - try { - WebSocketMessage msg = new TextMessage(mapper.writeValueAsString( - new BranchUpdateMessage(branch.getId(), branch.getStatus().name()) - )); - signalRepository.findAllConnectedToBranch(branch).stream() - .map(s -> getSignalWebSocketSession(s.getId())) - .filter(Objects::nonNull).distinct() - .forEach(session -> { - try { - session.sendMessage(msg); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - - } - - @Transactional(readOnly = true) - public SignalResponse getSignal(long rsId, long sigId) { - var s = signalRepository.findByIdAndRailSystemId(sigId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - return new SignalResponse(s); - } - - @Transactional(readOnly = true) - public List getAllSignals(long rsId) { - var rs = railSystemRepository.findById(rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Rail system not found.")); - return signalRepository.findAllByRailSystemOrderByName(rs).stream() - .map(SignalResponse::new) - .toList(); - } - - @Transactional - public void deleteSignal(long rsId, long sigId) { - var s = signalRepository.findByIdAndRailSystemId(sigId, rsId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - signalRepository.delete(s); - } -} diff --git a/src/main/java/nl/andrewl/railsignalapi/websocket/SignalWebSocketHandler.java b/src/main/java/nl/andrewl/railsignalapi/websocket/SignalWebSocketHandler.java index daf690e..81b2b1e 100644 --- a/src/main/java/nl/andrewl/railsignalapi/websocket/SignalWebSocketHandler.java +++ b/src/main/java/nl/andrewl/railsignalapi/websocket/SignalWebSocketHandler.java @@ -3,7 +3,6 @@ package nl.andrewl.railsignalapi.websocket; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import nl.andrewl.railsignalapi.service.SignalService; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; @@ -18,7 +17,6 @@ import java.util.Set; @Slf4j public class SignalWebSocketHandler extends TextWebSocketHandler { private final ObjectMapper mapper = new ObjectMapper(); - private final SignalService signalService; @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { @@ -31,19 +29,19 @@ public class SignalWebSocketHandler extends TextWebSocketHandler { for (var idStr : signalIdHeader.split(",")) { ids.add(Long.parseLong(idStr.trim())); } - signalService.registerSignalWebSocketSession(ids, session); + //signalService.registerSignalWebSocketSession(ids, session); log.info("Connection established with signals {}.", ids); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { var msg = mapper.readValue(message.getPayload(), SignalUpdateMessage.class); - signalService.handleSignalUpdate(msg); + //signalService.handleSignalUpdate(msg); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { - signalService.deregisterSignalWebSocketSession(session); + //signalService.deregisterSignalWebSocketSession(session); log.info("Closed connection {}. Status: {}", session.getId(), status.toString()); } } diff --git a/src/main/resources/static/js/drawing.js b/src/main/resources/static/js/drawing.js deleted file mode 100644 index 384a667..0000000 --- a/src/main/resources/static/js/drawing.js +++ /dev/null @@ -1,144 +0,0 @@ -function worldTransform() { - const canvasRect = railMapCanvas[0].getBoundingClientRect(); - const scale = SCALE_VALUES[canvasScaleIndex]; - let tx = new DOMMatrix(); - tx.translateSelf(canvasRect.width / 2, canvasRect.height / 2, 0); - tx.scaleSelf(scale, scale, scale); - tx.translateSelf(canvasTranslation.x, canvasTranslation.y, 0); - if (canvasDragOrigin !== null && canvasDragTranslation !== null) { - tx.translateSelf(canvasDragTranslation.x, canvasDragTranslation.y, 0); - } - return tx; -} - -function canvasPointToWorld(p) { - return worldTransform().invertSelf().transformPoint(p); -} - -function worldPointToCanvas(p) { - return worldTransform().transformPoint(p); -} - -function signalTransform(worldTx, signal) { - let tx = DOMMatrix.fromMatrix(worldTx); - tx.translateSelf(signal.position.x, signal.position.z, 0); - let direction = signal.branchConnections[0].direction; - if (direction === "EAST" || direction === "SOUTH" || direction === "SOUTH_EAST" || direction === "SOUTH_WEST") { - direction = signal.branchConnections[1].direction; - } - if (direction === undefined || direction === null || direction === "") { - direction = "NORTH"; - } - let angle = 0; - if (direction === "NORTH") { - angle = 90; - } else if (direction === "NORTH_WEST") { - angle = 45; - } else if (direction === "NORTH_EAST") { - angle = 135; - } - tx.rotateSelf(0, 0, angle); - return tx; -} - -function drawRailSystem() { - let ctx = railMapCanvas[0].getContext("2d"); - ctx.resetTransform(); - ctx.clearRect(0, 0, railMapCanvas.width(), railMapCanvas.height()); - const worldTx = worldTransform(); - ctx.setTransform(worldTx); - railSystem.signals.forEach(signal => { - drawReachableConnections(ctx, signal); - }); - railSystem.signals.forEach(signal => { - ctx.setTransform(signalTransform(worldTx, signal)); - drawSignal(ctx, signal); - }); - ctx.resetTransform(); - ctx.fillStyle = 'black'; - ctx.strokeStyle = 'black'; - ctx.font = '24px Serif'; - let textLine = 0; - hoveredElements.forEach(element => { - ctx.strokeText(element.name, 10, 20 + textLine * 20); - ctx.fillText(element.name, 10, 20 + textLine * 20); - textLine += 1; - }); -} - -function drawSignal(ctx, signal) { - if (signal.online) { - ctx.fillStyle = 'black'; - } else { - ctx.fillStyle = 'gray'; - } - ctx.scale(2, 2); - ctx.fillRect(-0.5, -0.5, 1, 1); - let northWesterlyCon = signal.branchConnections[0]; - let southEasterlyCon = signal.branchConnections[1]; - if (northWesterlyCon.direction === "EAST" || northWesterlyCon.direction === "SOUTH" || northWesterlyCon.direction === "SOUTH_WEST" || northWesterlyCon.direction === "SOUTH_EAST") { - let tmp = northWesterlyCon; - northWesterlyCon = southEasterlyCon; - southEasterlyCon = tmp; - } - - ctx.fillStyle = getSignalColor(signal, southEasterlyCon.branch.status); - ctx.fillRect(-0.75, -0.4, 0.3, 0.8); - ctx.fillStyle = getSignalColor(signal, northWesterlyCon.branch.status); - ctx.fillRect(0.45, -0.4, 0.3, 0.8); -} - -function getSignalColor(signal, branchStatus) { - if (!signal.online) return 'rgb(0, 0, 255)'; - if (branchStatus === "FREE") { - return 'rgb(0, 255, 0)'; - } else if (branchStatus === "OCCUPIED") { - return 'rgb(255, 0, 0)'; - } else { - return 'rgb(0, 0, 255)'; - } -} - -// Draws lines indicating reachable paths between this signal and others, with arrows for directionality. -function drawReachableConnections(ctx, signal) { - ctx.strokeStyle = 'black'; - ctx.lineWidth = 0.25; - signal.branchConnections.forEach(connection => { - ctx.resetTransform(); - connection.reachableSignalConnections.forEach(reachableCon => { - const dx = reachableCon.signalPosition.x - signal.position.x; - const dy = reachableCon.signalPosition.z - signal.position.z; - const dist = Math.sqrt(dx * dx + dy * dy); - let tx = worldTransform(); - tx.translateSelf(signal.position.x, signal.position.z, 0); - const angle = Math.atan2(dy, dx) * 180 / Math.PI - 90; - tx.rotateSelf(0, 0, angle); - ctx.setTransform(tx); - ctx.beginPath(); - ctx.moveTo(0, 0); - ctx.lineTo(0, dist); - const arrowEnd = 5; - const arrowWidth = 0.5; - const arrowLength = 1; - ctx.lineTo(0, arrowEnd); - ctx.lineTo(arrowWidth, arrowEnd - arrowLength); - ctx.lineTo(-arrowWidth, arrowEnd - arrowLength); - ctx.lineTo(0, arrowEnd); - ctx.stroke(); - ctx.fill(); - }); - }); -} - -function getRailSystemBoundingBox() { - let min = {x: Number.MAX_SAFE_INTEGER, z: Number.MAX_SAFE_INTEGER}; - let max = {x: Number.MIN_SAFE_INTEGER, z: Number.MIN_SAFE_INTEGER}; - railSystem.signals.forEach(signal => { - let p = signal.position; - if (p.x < min.x) min.x = p.x; - if (p.z < min.z) min.z = p.z; - if (p.x > max.x) max.x = p.x; - if (p.z > max.z) max.z = p.z; - }); - return {x: min.x, y: min.z, width: Math.abs(max.x - min.x), height: Math.abs(max.z - min.z)}; -} \ No newline at end of file diff --git a/src/main/resources/static/js/main.js b/src/main/resources/static/js/main.js deleted file mode 100644 index 481ccf4..0000000 --- a/src/main/resources/static/js/main.js +++ /dev/null @@ -1,388 +0,0 @@ -const $ = jQuery; - -let railSystemSelect; -let railMapCanvas; -let railSystem = null; -let detailPanel = null; - -let canvasTranslation = {x: 0, y: 0}; -let canvasDragOrigin = null; -let canvasDragTranslation = null; -let hoveredElements = []; - -const SCALE_VALUES = [0.01, 0.1, 0.25, 0.5, 1.0, 1.25, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0, 20.0, 30.0, 45.0, 60.0, 80.0, 100.0]; -const SCALE_INDEX_NORMAL = 7; -let canvasScaleIndex = SCALE_INDEX_NORMAL; - -$(document).ready(() => { - railSystemSelect = $('#railSystemSelect'); - railSystemSelect.change(railSystemChanged); - - railMapCanvas = $('#railMapCanvas'); - railMapCanvas.on('wheel', onCanvasMouseWheel); - railMapCanvas.mousedown(onCanvasMouseDown); - railMapCanvas.mouseup(onCanvasMouseUp); - railMapCanvas.mousemove(onCanvasMouseMove); - - $('#addRailSystemInput').on("input", () => { - $('#addRailSystemButton').prop("disabled", $('#addRailSystemInput').val() === ""); - }); - $('#addRailSystemButton').click(addRailSystem); - $('#removeRailSystemButton').click(deleteRailSystem); - - detailPanel = $('#railMapDetailPanel'); - - refreshRailSystems(true); -}); - -// Handle mouse scrolling within the context of the canvas. -function onCanvasMouseWheel(event) { - let s = event.originalEvent.deltaY; - if (s > 0) { - canvasScaleIndex = Math.max(0, canvasScaleIndex - 1); - } else if (s < 0) { - canvasScaleIndex = Math.min(SCALE_VALUES.length - 1, canvasScaleIndex + 1); - } - drawRailSystem(); - event.stopPropagation(); -} - -// Handle mouse clicks on the canvas. -function onCanvasMouseDown(event) { - const p = getMousePoint(event); - canvasDragOrigin = {x: p.x, y: p.y}; -} - -// Handle mouse release on the canvas, which stops dragging or indicates that the user may have clicked on something. -function onCanvasMouseUp(event) { - if (canvasDragTranslation !== null) { - canvasTranslation.x += canvasDragTranslation.x; - canvasTranslation.y += canvasDragTranslation.y; - } else { - const p = getMousePoint(event); - let signalClicked = false; - railSystem.signals.forEach(signal => { - const sp = new DOMPoint(signal.position.x, signal.position.z, 0, 1); - const canvasSp = worldPointToCanvas(sp); - const dist = Math.sqrt(Math.pow(p.x - canvasSp.x, 2) + Math.pow(p.y - canvasSp.y, 2)); - if (dist < 5) { - console.log(signal); - onSignalSelected(signal); - signalClicked = true; - } - }); - if (!signalClicked) { - onSignalSelected(null); - } - } - canvasDragOrigin = null; - canvasDragTranslation = null; -} - -// Handle mouse motion over the canvas. This is for dragging and hovering over items. -function onCanvasMouseMove(event) { - const rect = railMapCanvas[0].getBoundingClientRect(); - const x = event.clientX - rect.left; - const y = event.clientY - rect.top; - if (canvasDragOrigin !== null) { - const scale = SCALE_VALUES[canvasScaleIndex]; - const dx = x - canvasDragOrigin.x; - const dy = y - canvasDragOrigin.y; - canvasDragTranslation = {x: dx / scale, y: dy / scale}; - drawRailSystem(); - } else { - hoveredElements = []; - const p = getMousePoint(event); - railSystem.signals.forEach(signal => { - const sp = new DOMPoint(signal.position.x, signal.position.z, 0, 1); - const canvasSp = worldPointToCanvas(sp); - const dist = Math.sqrt(Math.pow(p.x - canvasSp.x, 2) + Math.pow(p.y - canvasSp.y, 2)); - if (dist < 5) { - hoveredElements.push(signal); - } - }); - drawRailSystem(); - } -} - -function getMousePoint(event) { - const rect = railMapCanvas[0].getBoundingClientRect(); - const x = event.clientX - rect.left; - const y = event.clientY - rect.top; - return new DOMPoint(x, y, 0, 1); -} - -function railSystemChanged() { - detailPanel.empty(); - railSystem = {}; - railSystem.id = railSystemSelect.val(); - $.get("/api/railSystems/" + railSystem.id + "/signals") - .done(signals => { - railSystem.signals = signals; - let bb = getRailSystemBoundingBox(); - canvasTranslation.x = -1 * (bb.x + (bb.width / 2)); - canvasTranslation.y = -1 * (bb.y + (bb.height / 2)); - canvasScaleIndex = SCALE_INDEX_NORMAL; - drawRailSystem(); - window.setInterval(railSystemUpdated, 1000); - }); - $.get("/api/railSystems/" + railSystem.id + "/branches") - .done(branches => { - railSystem.branches = branches; - const branchSelects = $('.js_branch_list'); - branchSelects.empty(); - railSystem.branches.forEach(branch => { - branchSelects.append($('')) - }); - }); -} - -// Updates the current rail system's information from the API. -function railSystemUpdated() { - $.get("/api/railSystems/" + railSystem.id + "/signals") - .done(signals => { - railSystem.signals = signals; - drawRailSystem(); - }); - $.get("/api/railSystems/" + railSystem.id + "/branches") - .done(branches => { - railSystem.branches = branches; - const branchSelects = $('.js_branch_list'); - branchSelects.empty(); - railSystem.branches.forEach(branch => { - branchSelects.append($('')) - }); - }); -} - -function selectSignalById(id) { - railSystem.signals.forEach(signal => { - if (signal.id === id) { - onSignalSelected(signal); - } - }); -} - -function onSignalSelected(signal) { - detailPanel.empty(); - if (signal !== null) { - const tpl = Handlebars.compile($('#signalTemplate').html()); - detailPanel.html(tpl(signal)); - signal.branchConnections.forEach(con => { - const select = $('#signalPotentialConnectionsSelect-' + con.id); - $.get("/api/railSystems/" + railSystem.id + "/branches/" + con.branch.id + "/signals") - .done(signals => { - signals = signals.filter(s => s.id !== signal.id); - let connections = []; - signals.forEach(s => { - s.branchConnections - .filter(c => c.branch.id === con.branch.id && !con.reachableSignalConnections.some(rc => rc.connectionId === c.id)) - .forEach(potentialConnection => { - potentialConnection.signalName = s.name; - potentialConnection.signalId = s.id; - connections.push(potentialConnection); - }); - }); - select.empty(); - const row = $('#signalPotentialConnectionsRow-' + con.id); - row.toggle(connections.length > 0); - connections.forEach(c => { - select.append($(``)) - }); - }); - }); - } -} - -function addRailSystem() { - let name = $('#addRailSystemInput').val().trim(); - $.post({ - url: "/api/railSystems", - data: JSON.stringify({name: name}), - contentType: "application/json" - }) - .done((response) => { - refreshRailSystems(); - }) - .always(() => { - $('#addRailSystemInput').val(""); - }); -} - -function deleteRailSystem() { - if (railSystem !== null && railSystem.id) { - confirm("Are you sure you want to permanently remove rail system " + railSystem.id + "?") - .then(() => { - $.ajax({ - url: "/api/railSystems/" + railSystem.id, - type: "DELETE" - }) - .always(() => { - refreshRailSystems(true); - }); - }); - } -} - -function refreshRailSystems(selectFirst) { - $.get("/api/railSystems") - .done(railSystems => { - railSystemSelect.empty(); - railSystems.forEach(railSystem => { - let option = $(``) - railSystemSelect.append(option); - }); - if (selectFirst) { - railSystemSelect.val(railSystems[0].id); - railSystemSelect.change(); - } - }); -} - -function addNewSignal() { - const modalElement = $('#addSignalModal'); - const form = $('#addSignalForm'); - form.validate(); - if (!form.valid()) return; - const data = { - name: $('#addSignalName').val().trim(), - position: { - x: $('#addSignalPositionX').val(), - y: $('#addSignalPositionY').val(), - z: $('#addSignalPositionZ').val() - }, - branchConnections: [ - { - direction: $('#addSignalFirstConnectionDirection').val(), - name: $('#addSignalFirstConnectionBranch').val() - }, - { - direction: $('#addSignalSecondConnectionDirection').val(), - name: $('#addSignalSecondConnectionBranch').val() - } - ] - }; - const modal = bootstrap.Modal.getInstance(modalElement[0]); - modal.hide(); - modalElement.on("hidden.bs.modal", () => { - confirm("Are you sure you want to add this new signal to the system?") - .then(() => { - $.post({ - url: "/api/railSystems/" + railSystem.id + "/signals", - data: JSON.stringify(data), - contentType: "application/json" - }) - .done(() => { - form.trigger("reset"); - railSystemUpdated(); - }) - .fail((response) => { - console.error(response); - $('#addSignalAlertsContainer').append($('
An error occurred.
')); - modal.show(); - }); - }) - .catch(() => { - form.trigger("reset"); - }); - }); -} - -function removeSignal(signalId) { - confirm(`Are you sure you want to remove signal ${signalId}? This cannot be undone.`) - .then(() => { - $.ajax({ - url: `/api/railSystems/${railSystem.id}/signals/${signalId}`, - type: "DELETE" - }) - .always(() => { - railSystemUpdated(); - }) - .fail((response) => { - console.error(response); - }) - }) -} - -function removeReachableConnection(signalId, fromId, toId) { - confirm(`Are you sure you want to remove the connection from ${fromId} to ${toId} from signal ${signalId}?`) - .then(() => { - $.get(`/api/railSystems/${railSystem.id}/signals/${signalId}`) - .done(signal => { - let connections = []; - signal.branchConnections.forEach(con => { - con.reachableSignalConnections.forEach(reachableCon => { - connections.push({from: con.id, to: reachableCon.connectionId}); - }); - }); - connections = connections.filter(c => !(c.from === fromId && c.to === toId)); - $.post({ - url: `/api/railSystems/${railSystem.id}/signals/${signal.id}/signalConnections`, - data: JSON.stringify({connections: connections}), - contentType: "application/json" - }) - .done(() => { - railSystemUpdated(); - }) - .fail((response) => { - console.error(response); - }); - }); - }); -} - -function addReachableConnectionBtn(signalId, fromId) { - const select = $('#signalPotentialConnectionsSelect-' + fromId); - const toId = select.val(); - if (toId) { - addReachableConnection(signalId, fromId, toId); - } -} - -function addReachableConnection(signalId, fromId, toId) { - confirm(`Are you sure you want to add a connection from ${fromId} to ${toId} from signal ${signalId}?`) - .then(() => { - $.get(`/api/railSystems/${railSystem.id}/signals/${signalId}`) - .done(signal => { - let connections = []; - signal.branchConnections.forEach(con => { - con.reachableSignalConnections.forEach(reachableCon => { - connections.push({from: con.id, to: reachableCon.connectionId}); - }); - }); - if (!connections.find(c => c.from === fromId && c.to === toId)) { - connections.push({from: fromId, to: toId}); - $.post({ - url: `/api/railSystems/${railSystem.id}/signals/${signal.id}/signalConnections`, - data: JSON.stringify({connections: connections}), - contentType: "application/json" - }) - .done(() => { - railSystemChanged(); - }) - .fail((response) => { - console.error(response); - }); - } - }); - }); -} - -function confirm(message) { - const modalElement = $('#confirmModal'); - if (message) { - $('#confirmModalBody').html(message); - } else { - $('#confirmModalBody').html("Are you sure you want to continue?"); - } - const modal = new bootstrap.Modal(modalElement[0], {keyboard: false}); - modal.show(); - return new Promise((resolve, reject) => { - $('#confirmModalOkButton').click(() => { - modalElement.on("hidden.bs.modal", () => resolve()); - }); - $('#confirmModalCancelButton').click(() => { - modalElement.on("hidden.bs.modal", () => reject()); - }); - }); -} diff --git a/src/main/resources/static/style/main.css b/src/main/resources/static/style/main.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html deleted file mode 100644 index 7e80408..0000000 --- a/src/main/resources/templates/index.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - RailSignal - - - - - - - - -
-

RailSignal

-

Stay in control of your rails.

- -
-
- -
-
- -
-
-
- - -
-
-
- -
-
- -
-
- -
-
- -
- -
-
- -
-
-
-
-
- -
- - - - - -
- - - - - - - - - - \ No newline at end of file