From 25ba754fcab334be378de42ffff6176b343bb3b6 Mon Sep 17 00:00:00 2001 From: fanferr <158005923+fanferr@users.noreply.github.com> Date: Tue, 19 May 2026 23:32:56 +0700 Subject: [PATCH] upload pertama --- .gitignore | 7 + backend/database.js | 44 + backend/package-lock.json | 2875 ++++++++ backend/package.json | 22 + backend/server.js | 265 + backend/simulate_rfid.js | 15 + backend/simulate_sensor.js | 54 + cleanup_data.js | 101 + firmware/calibrate.ino | 75 + .../calibrate_loadcell/calibrate_loadcell.ino | 61 + firmware/impact_monitor.ino | 363 + firmware/test_rfid_gain.ino | 59 + frontend/.gitignore | 24 + frontend/README.md | 16 + frontend/error-log.txt | Bin 0 -> 738 bytes frontend/eslint.config.js | 29 + frontend/index.html | 16 + frontend/jsconfig.json | 10 + frontend/package-lock.json | 6289 +++++++++++++++++ frontend/package.json | 48 + frontend/postcss.config.js | 6 + frontend/public/logo.png | Bin 0 -> 113566 bytes frontend/public/vite.svg | 1 + frontend/src/App.css | 42 + frontend/src/App.jsx | 119 + frontend/src/api/api.js | 41 + frontend/src/assets/react.svg | 1 + frontend/src/components/HistoryModal.jsx | 232 + frontend/src/components/ProtectedRoute.jsx | 12 + frontend/src/components/ui/badge.jsx | 31 + frontend/src/components/ui/button.jsx | 47 + frontend/src/components/ui/card.jsx | 57 + frontend/src/components/ui/dialog.jsx | 89 + frontend/src/components/ui/input.jsx | 19 + frontend/src/components/ui/label.jsx | 19 + frontend/src/components/ui/select.jsx | 137 + frontend/src/components/ui/separator.jsx | 25 + frontend/src/components/ui/table.jsx | 92 + frontend/src/context/AuthContext.jsx | 52 + frontend/src/context/SocketContext.jsx | 34 + frontend/src/firebase.js | 17 + frontend/src/index.css | 167 + frontend/src/lib/utils.js | 6 + frontend/src/main.jsx | 10 + frontend/src/pages/AdminLogin.jsx | 116 + frontend/src/pages/Dashboard.jsx | 376 + frontend/src/pages/Leaderboard.jsx | 630 ++ frontend/src/pages/LiveTest.jsx | 439 ++ frontend/src/pages/Monitor.jsx | 578 ++ frontend/src/pages/Register.jsx | 214 + frontend/src/pages/Settings.jsx | 250 + frontend/tailwind.config.js | 59 + frontend/vite.config.js | 12 + package-lock.json | 1058 +++ package.json | 5 + scratch_check_firebase.js | 47 + 56 files changed, 15413 insertions(+) create mode 100644 .gitignore create mode 100644 backend/database.js create mode 100644 backend/package-lock.json create mode 100644 backend/package.json create mode 100644 backend/server.js create mode 100644 backend/simulate_rfid.js create mode 100644 backend/simulate_sensor.js create mode 100644 cleanup_data.js create mode 100644 firmware/calibrate.ino create mode 100644 firmware/calibrate_loadcell/calibrate_loadcell.ino create mode 100644 firmware/impact_monitor.ino create mode 100644 firmware/test_rfid_gain.ino create mode 100644 frontend/.gitignore create mode 100644 frontend/README.md create mode 100644 frontend/error-log.txt create mode 100644 frontend/eslint.config.js create mode 100644 frontend/index.html create mode 100644 frontend/jsconfig.json create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/postcss.config.js create mode 100644 frontend/public/logo.png create mode 100644 frontend/public/vite.svg create mode 100644 frontend/src/App.css create mode 100644 frontend/src/App.jsx create mode 100644 frontend/src/api/api.js create mode 100644 frontend/src/assets/react.svg create mode 100644 frontend/src/components/HistoryModal.jsx create mode 100644 frontend/src/components/ProtectedRoute.jsx create mode 100644 frontend/src/components/ui/badge.jsx create mode 100644 frontend/src/components/ui/button.jsx create mode 100644 frontend/src/components/ui/card.jsx create mode 100644 frontend/src/components/ui/dialog.jsx create mode 100644 frontend/src/components/ui/input.jsx create mode 100644 frontend/src/components/ui/label.jsx create mode 100644 frontend/src/components/ui/select.jsx create mode 100644 frontend/src/components/ui/separator.jsx create mode 100644 frontend/src/components/ui/table.jsx create mode 100644 frontend/src/context/AuthContext.jsx create mode 100644 frontend/src/context/SocketContext.jsx create mode 100644 frontend/src/firebase.js create mode 100644 frontend/src/index.css create mode 100644 frontend/src/lib/utils.js create mode 100644 frontend/src/main.jsx create mode 100644 frontend/src/pages/AdminLogin.jsx create mode 100644 frontend/src/pages/Dashboard.jsx create mode 100644 frontend/src/pages/Leaderboard.jsx create mode 100644 frontend/src/pages/LiveTest.jsx create mode 100644 frontend/src/pages/Monitor.jsx create mode 100644 frontend/src/pages/Register.jsx create mode 100644 frontend/src/pages/Settings.jsx create mode 100644 frontend/tailwind.config.js create mode 100644 frontend/vite.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scratch_check_firebase.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92d29c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +backend/node_modules/ +frontend/node_modules/ +frontend/dist/ +backend/silat_monitor.db +.env +.DS_Store diff --git a/backend/database.js b/backend/database.js new file mode 100644 index 0000000..6e75871 --- /dev/null +++ b/backend/database.js @@ -0,0 +1,44 @@ +const sqlite3 = require('sqlite3').verbose(); +const path = require('path'); + +const dbPath = path.resolve(__dirname, 'silat_monitor.db'); +const db = new sqlite3.Database(dbPath, (err) => { + if (err) console.error('Error opening database:', err); + else console.log('Database initialized at', dbPath); +}); + +db.serialize(() => { + db.run(` + CREATE TABLE IF NOT EXISTS athletes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + age INTEGER, + height REAL, + weight REAL, + category TEXT, + rfid_tag TEXT UNIQUE + ) + `); + + db.run(` + CREATE TABLE IF NOT EXISTS attempts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + athlete_id INTEGER, + force REAL, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(athlete_id) REFERENCES athletes(id) + ) + `); + db.run(` + CREATE TABLE IF NOT EXISTS admins ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password TEXT NOT NULL + ) + `); + + // Inisialisasi admin default jika belum ada + db.run(`INSERT OR IGNORE INTO admins (username, password) VALUES ('admin', 'admin123')`); +}); + +module.exports = db; diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..59e7d1d --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,2875 @@ +{ + "name": "backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "cors": "^2.8.5", + "express": "^4.21.2", + "socket.io": "^4.8.1", + "sqlite3": "^5.1.7" + }, + "devDependencies": { + "nodemon": "^3.1.9" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT", + "optional": true + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", + "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", + "optional": true + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC", + "optional": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": 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==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", + "optional": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC", + "optional": 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==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.87.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", + "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "optional": 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==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", + "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.18.3" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/socket.io-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..beb349e --- /dev/null +++ b/backend/package.json @@ -0,0 +1,22 @@ +{ + "name": "backend", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "sqlite3": "^5.1.7", + "cors": "^2.8.5", + "express": "^4.21.2", + "socket.io": "^4.8.1" + }, + "devDependencies": { + "nodemon": "^3.1.9" + } +} \ No newline at end of file diff --git a/backend/server.js b/backend/server.js new file mode 100644 index 0000000..3c0383d --- /dev/null +++ b/backend/server.js @@ -0,0 +1,265 @@ +const express = require('express'); +const http = require('http'); +const { Server } = require("socket.io"); +const cors = require('cors'); +const db = require('./database'); + +const app = express(); +app.use(cors()); +app.use(express.json()); + +const server = http.createServer(app); +const io = new Server(server, { + cors: { + origin: "*", + methods: ["GET", "POST"] + } +}); + +let currentTestSession = { + athleteId: null, + attempts: [] +}; + +// Helper for Promisified DB queries +const dbAll = (sql, params = []) => { + return new Promise((resolve, reject) => { + db.all(sql, params, (err, rows) => { + if (err) reject(err); + else resolve(rows); + }); + }); +}; + +const dbGet = (sql, params = []) => { + return new Promise((resolve, reject) => { + db.get(sql, params, (err, row) => { + if (err) reject(err); + else resolve(row); + }); + }); +}; + +const dbRun = (sql, params = []) => { + return new Promise((resolve, reject) => { + db.run(sql, params, function (err) { + if (err) reject(err); + else resolve({ id: this.lastID, changes: this.changes }); + }); + }); +}; + + +// API Routes +app.get('/api/athletes', async (req, res) => { + try { + const athletes = await dbAll('SELECT * FROM athletes ORDER BY id DESC'); + res.json(athletes); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.get('/api/athletes/:id', async (req, res) => { + try { + const athlete = await dbGet('SELECT * FROM athletes WHERE id = ?', [req.params.id]); + if (athlete) res.json(athlete); + else res.status(404).json({ error: 'Athlete not found' }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.post('/api/athletes', async (req, res) => { + const { name, age, height, weight, category, rfid_tag } = req.body; + try { + const result = await dbRun( + 'INSERT INTO athletes (name, age, height, weight, category, rfid_tag) VALUES (?, ?, ?, ?, ?, ?)', + [name, age, height, weight, category, rfid_tag] + ); + res.json({ id: result.id, success: true }); + } catch (err) { + console.error(err); + res.status(500).json({ error: err.message }); + } +}); + +app.delete('/api/athletes/:id', async (req, res) => { + try { + await dbRun('DELETE FROM attempts WHERE athlete_id = ?', [req.params.id]); + await dbRun('DELETE FROM athletes WHERE id = ?', [req.params.id]); + res.json({ success: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.get('/api/leaderboard', async (req, res) => { + try { + const query = ` + SELECT a.name, a.category, MAX(at.force) as best_score + FROM athletes a + JOIN attempts at ON a.id = at.athlete_id + GROUP BY a.id, a.name, a.category + ORDER BY best_score DESC + `; + const leaderboard = await dbAll(query); + res.json(leaderboard); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.get('/api/attempts/:athleteId', async (req, res) => { + try { + const attempts = await dbAll( + 'SELECT * FROM attempts WHERE athlete_id = ? ORDER BY timestamp ASC', + [req.params.athleteId] + ); + res.json(attempts); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +// Get History for Chart (Option 3) +app.get('/api/history/:athleteId', async (req, res) => { + try { + const history = await dbAll(` + SELECT + strftime('%Y-%m-%d %H:%M', timestamp) as date, + force + FROM attempts + WHERE athlete_id = ? + ORDER BY timestamp ASC + `, [req.params.athleteId]); + res.json(history); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +// Start/Stop Test Session logic +app.post('/api/start-test', (req, res) => { + const { athleteId } = req.body; + // Reset session for this athlete + currentTestSession = { athleteId: parseInt(athleteId), attempts: [] }; + io.emit('session_started', { athleteId: currentTestSession.athleteId }); + console.log(`Session started for athlete ${athleteId}`); + res.json({ success: true }); +}); + +app.post('/api/stop-test', (req, res) => { + currentTestSession = { athleteId: null, attempts: [] }; + io.emit('session_ended'); + console.log(`Session ended`); + res.json({ success: true }); +}); + +app.post('/api/admin/login', async (req, res) => { + const { username, password } = req.body; + try { + const admin = await dbGet('SELECT * FROM admins WHERE username = ?', [username]); + if (admin && password === admin.password) { + res.json({ success: true, token: 'mock-admin-token', username: admin.username }); + } else { + res.status(401).json({ success: false, message: 'Username atau Password salah' }); + } + } catch (err) { + res.status(500).json({ error: 'Database error' }); + } +}); + +// Admin Management APIs +app.get('/api/admin/users', async (req, res) => { + try { + const admins = await dbAll('SELECT id, username FROM admins'); + res.json(admins); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.post('/api/admin/users', async (req, res) => { + const { username, password } = req.body; + try { + await dbRun('INSERT INTO admins (username, password) VALUES (?, ?)', [username, password]); + res.json({ success: true, message: 'Admin baru ditambahkan' }); + } catch (err) { + res.status(500).json({ error: 'Username sudah digunakan atau gagal simpan' }); + } +}); + +app.delete('/api/admin/users/:id', async (req, res) => { + try { + await dbRun('DELETE FROM admins WHERE id = ?', [req.params.id]); + res.json({ success: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.post('/api/admin/update-password', async (req, res) => { + const { username, oldPassword, newPassword } = req.body; + try { + const admin = await dbGet('SELECT * FROM admins WHERE username = ?', [username]); + if (!admin || oldPassword !== admin.password) { + return res.status(400).json({ success: false, message: 'Password lama salah' }); + } + await dbRun('UPDATE admins SET password = ? WHERE username = ?', [newPassword, username]); + res.json({ success: true, message: 'Password berhasil diubah' }); + } catch (err) { + res.status(500).json({ error: 'Gagal mengubah password' }); + } +}); + +// Socket.io +io.on('connection', (socket) => { + console.log('Client connected', socket.id); + + // Received from RFID reader (simulation) + socket.on('rfid_scan', (tagId) => { + console.log('RFID Scanned:', tagId); + io.emit('rfid_scanned', tagId); + }); + + // Received from Impact Sensor (simulation) + // Stream for graph visualization + socket.on('sensor_stream', (value) => { + io.emit('sensor_live_data', value); + }); + + // Impact detected (Peak value or significant hit) + socket.on('impact_detected', async (forceValue) => { + console.log('Impact detected:', forceValue); + + if (currentTestSession.athleteId) { + const athleteId = currentTestSession.athleteId; + + // Save to DB + try { + await dbRun('INSERT INTO attempts (athlete_id, force) VALUES (?, ?)', [athleteId, forceValue]); + + currentTestSession.attempts.push(forceValue); + const attemptCount = currentTestSession.attempts.length; + + io.emit('new_attempt_result', { + force: forceValue, + attemptNumber: attemptCount, + athleteId + }); + + if (attemptCount >= 3) { + io.emit('test_milestone_reached', { athleteId, count: 3 }); + } + } catch (err) { + console.error("Error saving attempt:", err); + } + } + }); +}); + +const PORT = 3000; +server.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); diff --git a/backend/simulate_rfid.js b/backend/simulate_rfid.js new file mode 100644 index 0000000..ad7de99 --- /dev/null +++ b/backend/simulate_rfid.js @@ -0,0 +1,15 @@ +const io = require('socket.io-client'); + +const socket = io('http://localhost:3000'); + +const tagId = process.argv[2] || 'TAG-' + Math.floor(Math.random() * 100000); + +socket.on('connect', () => { + console.log('Connected to server as RFID Reader'); + console.log(`Scanning tag: ${tagId}`); + socket.emit('rfid_scan', tagId); + + setTimeout(() => { + socket.disconnect(); + }, 1000); +}); diff --git a/backend/simulate_sensor.js b/backend/simulate_sensor.js new file mode 100644 index 0000000..441432d --- /dev/null +++ b/backend/simulate_sensor.js @@ -0,0 +1,54 @@ +const io = require('socket.io-client'); + +const socket = io('http://localhost:3000'); + +socket.on('connect', () => { + console.log('Connected to server as Impact Sensor'); + simulatePunch(); +}); + +function simulatePunch() { + console.log('Simulating punch...'); + + // 1. Send low noise (idle) + let steps = 0; + const idleInterval = setInterval(() => { + const noise = Math.random() * 5; + socket.emit('sensor_stream', noise); + steps++; + + if (steps > 20) { + clearInterval(idleInterval); + sendImpact(); + } + }, 50); +} + +function sendImpact() { + // 2. Send spike (Impact) + let force = 0; + const peak = 500 + Math.random() * 500; // Random peak between 500 and 1000 + let up = true; + + const impactInterval = setInterval(() => { + if (up) { + force += 100; + if (force >= peak) { + force = peak; + up = false; + // Emit event at peak + socket.emit('impact_detected', Math.round(peak)); + } + } else { + force -= 100; + if (force <= 0) { + force = 0; + clearInterval(impactInterval); + socket.emit('sensor_stream', 0); + console.log(`Punch finished. Peak: ${Math.round(peak)}`); + socket.disconnect(); // Or keep running for next punch + } + } + socket.emit('sensor_stream', force); + }, 20); // Fast update for impact +} diff --git a/cleanup_data.js b/cleanup_data.js new file mode 100644 index 0000000..41c2c63 --- /dev/null +++ b/cleanup_data.js @@ -0,0 +1,101 @@ +const { initializeApp } = require('./node_modules/firebase/app'); +const { getDatabase, ref, get, remove, set } = require('./node_modules/firebase/database'); +const sqlite3 = require('./backend/node_modules/sqlite3').verbose(); +const path = require('path'); + +const firebaseConfig = { + apiKey: "AIzaSyDhFtqvaTMgYH9vyAHFclDUXiOxkl-2GqM", + authDomain: "silat-b3100.firebaseapp.com", + databaseURL: "https://silat-b3100-default-rtdb.firebaseio.com/", + projectId: "silat-b3100", + storageBucket: "silat-b3100.firebasestorage.app", + messagingSenderId: "471266034969", + appId: "1:471266034969:web:467de19582cf2fd3da3188" +}; + +const app = initializeApp(firebaseConfig); +const rtdb = getDatabase(app); + +const todayStart = 1778691600000; // 14/05/2026 00:00:00 UTC+7 +const galihIds = ['026AB155', '23B29603']; + +async function cleanupFirebase() { + console.log("--- CLEANING FIREBASE ---"); + try { + const usersSnap = await get(ref(rtdb, 'users')); + const users = usersSnap.val() || {}; + const activeUserIds = Object.keys(users); + + const nodes = ['test_history', 'attempts']; + + for (const node of nodes) { + console.log(`Checking node: ${node}`); + const nodeSnap = await get(ref(rtdb, node)); + const data = nodeSnap.val() || {}; + + for (const id in data) { + const isGalih = galihIds.includes(id); + const isOrphan = !activeUserIds.includes(id); + + if (isGalih || isOrphan) { + console.log(`Processing ID: ${id} (${isGalih ? 'Galih' : 'Orphan'})`); + const sessions = data[id]; + + for (const sessionKey in sessions) { + let sessionTs = 0; + if (sessionKey.startsWith('session_')) { + sessionTs = parseInt(sessionKey.replace('session_', '')); + } else if (sessions[sessionKey].timestamp) { + sessionTs = sessions[sessionKey].timestamp; + } + + // Jika timestamp di bawah hari ini, hapus + if (sessionTs < todayStart) { + console.log(` Deleting old session: ${sessionKey} (TS: ${sessionTs})`); + await remove(ref(rtdb, `${node}/${id}/${sessionKey}`)); + } else { + console.log(` KEEPING today's session: ${sessionKey} (TS: ${sessionTs})`); + } + } + } + } + } + console.log("Firebase cleanup done."); + } catch (err) { + console.error("Firebase Error:", err); + } +} + +function cleanupSQLite() { + console.log("\n--- CLEANING SQLITE ---"); + const dbPath = path.resolve(__dirname, 'backend', 'silat_monitor.db'); + const db = new sqlite3.Database(dbPath); + + db.serialize(() => { + // Hapus atlet yang tidak ada di list user baru (yang TEST- ID nya tidak valid lagi) + // Dan hapus attempts lama + + // Cari ID atlet yang namanya Fani/Ferdi yang lama + db.run("DELETE FROM attempts WHERE timestamp < datetime(1778691600/1000, 'unixepoch')", (err) => { + if (err) console.error("Error deleting old attempts:", err); + else console.log("Deleted old attempts in SQLite."); + }); + + // Hapus atlet yang RFID nya diawali TEST- (Data simulasi lama) + db.run("DELETE FROM athletes WHERE rfid_tag LIKE 'TEST-%'", (err) => { + if (err) console.error("Error deleting old athletes:", err); + else console.log("Deleted old athletes (TEST-) in SQLite."); + }); + }); + + db.close(); +} + +async function main() { + await cleanupFirebase(); + cleanupSQLite(); + console.log("\n✅ ALL CLEANUP TASKS COMPLETED."); + process.exit(); +} + +main(); diff --git a/firmware/calibrate.ino b/firmware/calibrate.ino new file mode 100644 index 0000000..824893d --- /dev/null +++ b/firmware/calibrate.ino @@ -0,0 +1,75 @@ +#include "HX711.h" + +// PIN HX711 ke ESP32 +#define DT_PIN 32 +#define SCK_PIN 33 + +HX711 scale; + +// ⚠️ Mode Kalibrasi Multi-Titik (Piecewise Linear) +// Rumus tunggal diganti dengan pemetaan khusus agar 1.1, 1.8, dan 3.65 akurat semua. + +// Batas nol (anti noise) +float zero_threshold = 0.2; + +// Fungsi Kalibrasi Multi-Titik untuk menyelaraskan semua beban +float hitung_berat_akurat(float raw) { + float r0 = 0.0, w0 = 0.0; + float r1 = 20185.0, w1 = 1.1; + float r2 = 30154.0, w2 = 1.8; + float r3 = 62972.0, w3 = 3.65; + + if (raw <= r0) return 0.0; + if (raw <= r1) return w0 + (raw - r0) * (w1 - w0) / (r1 - r0); + if (raw <= r2) return w1 + (raw - r1) * (w2 - w1) / (r2 - r1); + if (raw <= r3) return w2 + (raw - r2) * (w3 - w2) / (r3 - r2); + + // Ekstrapolasi untuk beban lebih dari 3.65kg (Pukulan) + return w3 + (raw - r3) * (w3 - w2) / (r3 - r2); +} + +void setup() { + Serial.begin(115200); + delay(1000); + + scale.begin(DT_PIN, SCK_PIN); + + Serial.println("=== LOADCELL START ==="); + Serial.println("Pastikan TIDAK ADA BEBAN di timbangan"); + delay(3000); + + // Set kalibrasi ke 1 karena kita menghitung manual berdasarkan nilai mentah (raw) + scale.set_scale(1.0); + + // Jadikan posisi sekarang = 0 + scale.tare(); + + Serial.println("Timbangan SIAP!"); +} + +void loop() { + // Gunakan 1 kali bacaan nilai mentah (raw value) tanpa jeda + float raw = scale.get_value(1); + + // Hitung berat menggunakan pemetaan multi-titik + float berat = hitung_berat_akurat(raw); + + // ========================= + // FILTER AGAR 0 BERSIH + // ========================= + // Jika sering tidak kembali ke 0 (nyangkut di 0.3 atau 0.4), naikkan zero_threshold di atas! + if (abs(berat) < zero_threshold) { + berat = 0; + } else if (berat < 0) { + berat = 0; // Abaikan kalau minus + } + + // ========================= + // TAMPILKAN HASIL + // ========================= + Serial.print("Berat: "); + Serial.print(berat, 2); + Serial.println(" kg"); + + delay(100); // Dipercepat agar kembalinya ke 0 terlihat seketika +} diff --git a/firmware/calibrate_loadcell/calibrate_loadcell.ino b/firmware/calibrate_loadcell/calibrate_loadcell.ino new file mode 100644 index 0000000..ec5d353 --- /dev/null +++ b/firmware/calibrate_loadcell/calibrate_loadcell.ino @@ -0,0 +1,61 @@ +#include "HX711.h" + +// Pin disesuaikan dengan ESP32 Anda di impact_monitor.ino +#define DT_PIN 32 +#define SCK_PIN 33 + +HX711 scale; + +// Silakan sesuaikan nilai ini untuk load cell 50kg saat melakukan kalibrasi +float calibration_factor = 103.8; +float threshold = 2.0; + +unsigned long emptyStartTime = 0; +bool isEmpty = false; + +void setup() { + Serial.begin(115200); + delay(1000); + + scale.begin(DT_PIN, SCK_PIN); + + Serial.println("Jangan ada beban..."); + delay(3000); + + scale.set_scale(calibration_factor); + scale.tare(); + + Serial.println("Timbangan siap!"); +} + +void loop() { + float berat = scale.get_units(20); + + // === DETEKSI KONDISI KOSONG === + if (abs(berat) < threshold) { + + if (!isEmpty) { + // baru masuk kondisi kosong + emptyStartTime = millis(); + isEmpty = true; + } + + // kalau sudah kosong selama 2 detik → tare + if (millis() - emptyStartTime > 2000) { + scale.tare(); + berat = 0; + } + + } else { + // ada beban → reset status kosong + isEmpty = false; + } + + float berat_kg = berat / 1000.0; + + Serial.print("Berat: "); + Serial.print(berat_kg, 1); + Serial.println(" kg"); + + delay(300); +} diff --git a/firmware/impact_monitor.ino b/firmware/impact_monitor.ino new file mode 100644 index 0000000..8dc5214 --- /dev/null +++ b/firmware/impact_monitor.ino @@ -0,0 +1,363 @@ +#include +#include +#include "HX711.h" +#include +#include +#include "time.h" + +// ================= WIFI ================= +#define WIFI_SSID "MalaikatIzrail" +#define WIFI_PASSWORD "12345678910" + +// ================= FIREBASE ================= +#define API_KEY "AIzaSyDhFtqvaTMgYH9vyAHFclDUXiOxkl-2GqM" +#define DATABASE_URL "https://silat-b3100-default-rtdb.firebaseio.com/" + +#define USER_EMAIL "faniferdiyanto1980@gmail.com" +#define USER_PASSWORD "faniferdiyanto80" + +// ================= PIN ================= +#define SS_PIN 21 +#define RST_PIN 22 +#define DT_PIN 32 +#define SCK_PIN 33 + +MFRC522 rfid(SS_PIN, RST_PIN); +HX711 scale; + +// ================= FIREBASE ================= +FirebaseData fbdo; +FirebaseData fbdoStream; // Dedicated stream object for test_command +FirebaseAuth auth; +FirebaseConfig config; +bool firebaseReady = false; + +// ================= VARIABEL ================= +float calibration_factor = 17740.0; +float offset_manual = 0.10; +float alpha = 0.95; // Ditingkatkan agar merespon lebih cepat / instan +float threshold = 2.5; // PERBAIKAN: Dinaikkan ke 2.5 KG agar lebih aman dari noise dan pergeseran mekanis +float smoothedWeight = 0; +float peakValue = 0; + +// Test variables +String currentTestUID = ""; +int currentAttempt = 1; +String currentStrikeType = "pukulan"; // Default +bool isTesting = false; +unsigned long testStartTime = 0; +unsigned long firstHitTime = 0; // Waktu saat pukulan pertama dideteksi +String handledCommand = ""; // Menghindari pengulangan perintah yang sama +const unsigned long TEST_DURATION = 5000; + +float graphData[100]; +int graphIndex = 0; + +// Timer Optimasi +unsigned long lastFirebaseUpdate = 0; +const unsigned long FIREBASE_UPDATE_INTERVAL = 300; // Lebih cepat: 100ms +unsigned long lastSampleTime = 0; +const unsigned long SAMPLING_INTERVAL = 30; // Lebih cepat: 30ms + +// PERBAIKAN: Throttle checkTestCommand agar tidak blocking setiap loop +unsigned long lastCommandCheck = 0; +const unsigned long COMMAND_CHECK_INTERVAL = 500; // Cek perintah setiap 500ms saja + +// ================= DATA LOGGING ================= +String getUID() { + String uid = ""; + for (byte i = 0; i < rfid.uid.size; i++) { + if (rfid.uid.uidByte[i] < 0x10) uid += "0"; + uid += String(rfid.uid.uidByte[i], HEX); + } + uid.toUpperCase(); + return uid; +} + +void syncTime() { + configTime(0, 0, "pool.ntp.org", "time.nist.gov", "time.google.com"); + Serial.print("Sync time"); + time_t now = time(nullptr); + int attempts = 0; + while (now < 100000 && attempts < 40) { + delay(500); + Serial.print("."); + now = time(nullptr); + attempts++; + } + if (now >= 100000) Serial.println("\n✅ Time synchronized"); + else Serial.println("\n⚠️ Time sync failed"); +} + +void initFirebase() { + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + config.timeout.serverResponse = 10000; + + // PERBAIKAN: Memperbesar buffer TX menjadi 4096 byte agar mampu menampung paket JSON grafik sekaligus! + fbdo.setBSSLBufferSize(4096, 4096); + fbdo.setResponseSize(2048); + fbdoStream.setBSSLBufferSize(2048, 512); + + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + Serial.println("🔥 Firebase Initialized"); +} + +void updateSensorStatus() { + if (firebaseReady) { + // Tulis Unix timestamp agar dashboard bisa deteksi kapan terakhir aktif + time_t now = time(nullptr); + Firebase.RTDB.setString(&fbdo, "/system/sensor_status", "Online"); + Firebase.RTDB.setInt(&fbdo, "/system/last_seen", (int)now); + } +} + +void handleRFIDScan() { + if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return; + String uid = getUID(); + Serial.println("RFID detected: " + uid); + Firebase.RTDB.setString(&fbdo, "/system/last_scanned", uid); + delay(1000); + rfid.PICC_HaltA(); + rfid.PCD_StopCrypto1(); +} + +float kgToNewton(float kg) { return kg * 9.81; } + +void checkTestCommand() { + if (isTesting) return; + + if (millis() - lastCommandCheck < COMMAND_CHECK_INTERVAL) return; + lastCommandCheck = millis(); + + if (Firebase.RTDB.get(&fbdoStream, "/test_command")) { + String command = fbdoStream.stringData(); + + // PERBAIKAN: Hanya jalan jika perintah baru (cegah loop otomatis) + if (command != "" && command != "null" && command != handledCommand && command.indexOf('|') > 0) { + handledCommand = command; // Tandai perintah sudah ditangani + + int firstSep = command.indexOf('|'); + int secondSep = command.indexOf('|', firstSep + 1); + + currentTestUID = command.substring(0, firstSep); + + if (secondSep > 0) { + currentAttempt = command.substring(firstSep + 1, secondSep).toInt(); + currentStrikeType = command.substring(secondSep + 1); + } else { + currentAttempt = command.substring(firstSep + 1).toInt(); + currentStrikeType = "pukulan"; // Fallback + } + + Serial.println("--- TEST STARTED ---"); + Serial.print("UID: "); Serial.println(currentTestUID); + Serial.print("Attempt: "); Serial.println(currentAttempt); + Serial.print("Type: "); Serial.println(currentStrikeType); + + isTesting = true; + testStartTime = millis(); + firstHitTime = 0; + peakValue = 0; + smoothedWeight = 0; + graphIndex = 0; + memset(graphData, 0, sizeof(graphData)); + + Firebase.RTDB.setFloat(&fbdo, "/realtime/current_force", 0); + Firebase.RTDB.setFloat(&fbdo, "/realtime/peak_force", 0); + Firebase.RTDB.setString(&fbdo, "/system/test_status", "measuring"); + Firebase.RTDB.setString(&fbdo, "/test_command", ""); // Bersihkan perintah + + // PERBAIKAN: Reset angka di layar dan nol-kan sensor tepat sebelum mulai + FirebaseJson rtReset; + rtReset.set("current_force", 0); + rtReset.set("peak_force", 0); + Firebase.RTDB.updateNode(&fbdo, "/realtime", &rtReset); + + scale.tare(); // Nol-kan sensor untuk menghilangkan drift dari pukulan sebelumnya + } + } +} + +void sendRealtimeData() { + if (!isTesting || !firebaseReady) return; + + if (millis() - lastFirebaseUpdate > FIREBASE_UPDATE_INTERVAL) { + lastFirebaseUpdate = millis(); + + float newton = kgToNewton(smoothedWeight); + float peakNewton = kgToNewton(peakValue); + + // MENGGUNAKAN Async DENGAN UPDATE NODE UNTUK MENGURANGI SPAM (Mencegah SSL Crash) + FirebaseJson rtJson; + rtJson.set("current_force", newton); + rtJson.set("peak_force", peakNewton); + Firebase.RTDB.updateNodeAsync(&fbdo, "/realtime", &rtJson); + + // PENGIRIMAN GRAFIK REALTIME DIHAPUS: + // Mengirim titik grafik satu-per-satu setiap 300ms ke Firebase membebani memori SSL (menyebabkan Error mRunUntil). + // Grafik akan langsung dikirim sekaligus dalam format JSON pada saat SaveResult (jauh lebih cepat & aman). + } +} + +void saveTestResult() { + if (!firebaseReady) return; + float peakNewton = kgToNewton(peakValue); + + // Jika diberhentikan manual / tidak ada benturan + if (peakValue <= threshold) { + Serial.println("⚠️ No impact detected, skipping save."); + // Gunakan JSON agar reset dikirim dalam 1x request cepat (mencegah error SSL) + FirebaseJson resetJson; + resetJson.set("realtime/current_force", 0); + resetJson.set("realtime/peak_force", 0); + resetJson.set("system/test_status", "idle"); + resetJson.set("test_command", ""); + + // PERBAIKAN: Hanya bersihkan memori Anti-Spam JIKA perintah reset berhasil dikirim ke Firebase! + // Ini mencegah "tombol mulai ngeklik sendiri" jika internet sempat putus. + if (Firebase.RTDB.updateNode(&fbdo, "/", &resetJson)) { + handledCommand = ""; + } else { + Serial.println("❌ Gagal mereset status, mencegah infinite loop."); + } + return; + } + + Serial.println("--- SAVING RESULT ---"); + String historyPath = "/test_history/" + currentTestUID + "/attempt_" + String(currentAttempt); + + // 1. Gabungkan semua data histori dalam 1 Paket JSON! + FirebaseJson historyJson; + historyJson.set("peak_kg", peakValue); + historyJson.set("peak_newton", peakNewton); + historyJson.set("type", currentStrikeType); + historyJson.set("timestamp", millis()); + + FirebaseJson graphJson; + for (int i = 0; i < graphIndex && i < 100; i++) { + graphJson.set(String(i), graphData[i]); + } + historyJson.set("graph", graphJson); + Firebase.RTDB.setJSON(&fbdo, historyPath, &historyJson); + + // 2. Tampilkan hasil akhir di layar besar (Persistence) ditangani oleh Website + // menggunakan data dari histori di atas, sehingga kita tidak perlu kirim ulang ke realtime/current_force + // hal ini mencegah munculnya "puncak ganda" di grafik. + + // 3. Reset Status Sistem + FirebaseJson statusReset; + statusReset.set("system/test_status", "idle"); + statusReset.set("test_command", ""); + + if (Firebase.RTDB.updateNode(&fbdo, "/", &statusReset)) { + handledCommand = ""; + } + Serial.println("✅ Result Saved!"); +} + +void readLoadcell() { + if (!scale.is_ready()) return; + + float raw = scale.get_units(1); + raw = raw + offset_manual; // Tambahkan hasil offset kalibrasi Anda + + if (raw < 0) raw = 0; // Abaikan minus + + // PERBAIKAN: Potong semua getaran ringan (di bawah 1.5 KG) menjadi 0. + // Ini mencegah munculnya angka "1" atau "2" Newton di layar akibat noise sensor! + if (raw < threshold) { + raw = 0; + } + + // KUNCI RESPONSIVITAS: Gunakan data mentah (raw) untuk mendeteksi puncak, bukan data yang sudah dihaluskan! + if (raw > peakValue) peakValue = raw; + + smoothedWeight = (alpha * raw) + ((1 - alpha) * smoothedWeight); + if (smoothedWeight < threshold) smoothedWeight = 0; + + if (isTesting && millis() - lastSampleTime > SAMPLING_INTERVAL) { + lastSampleTime = millis(); + if (graphIndex < 100) { + graphData[graphIndex] = kgToNewton(raw); // Gunakan raw juga agar grafik tidak terpotong (halus akan menahan data sejenak) + graphIndex++; + } + } + + if (isTesting) { + sendRealtimeData(); + + // 1. Deteksi Pukulan Pertama (Auto-Stop Trigger) + if (raw > threshold && firstHitTime == 0) { + firstHitTime = millis(); + Serial.println("🎯 Impact detected! Auto-stop in 3 seconds..."); + } + + // 2. Cek Auto-Stop (3 detik setelah pukulan) + if (firstHitTime > 0 && (millis() - firstHitTime > 3000)) { + Serial.println("⏹️ Auto-stop triggered"); + isTesting = false; + saveTestResult(); + firstHitTime = 0; + } + // 3. PERBAIKAN: Ganti pengecekan tombol Stop manual dengan Timeout otomatis (30 detik) + // Ini menghilangkan proses "blocking" saat mengambil data dari Firebase yang bikin Pukulan Delay! + else if (firstHitTime == 0 && (millis() - testStartTime > 30000)) { + Serial.println("⏳ Timeout, no impact detected."); + isTesting = false; + saveTestResult(); + } + } +} + +void setup() { + Serial.begin(115200); + delay(1000); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } + + syncTime(); + initFirebase(); + while (!Firebase.ready()) delay(100); + firebaseReady = true; + + Firebase.RTDB.setString(&fbdo, "/system/test_status", "idle"); + Firebase.RTDB.setString(&fbdo, "/test_command", ""); + + SPI.begin(); + rfid.PCD_Init(); + + // PERBAIKAN: Kekuatan antena RFID + // Disetel ke 38dB sesuai hasil pengetesan. Level ini paling stabil dan responsif + // untuk menembus kotak plastik 2mm tanpa membuat modul RC522 crash/blank. + rfid.PCD_SetAntennaGain(rfid.RxGain_38dB); + + scale.begin(DT_PIN, SCK_PIN); + delay(2000); + + // Set kalibrasi dengan angka yang sudah fix + scale.set_scale(calibration_factor); + scale.tare(); + + Serial.println("🚀 SYSTEM READY"); +} + +void loop() { + if (Firebase.ready()) { + readLoadcell(); + checkTestCommand(); + + static unsigned long lastStatusUpdate = 0; + if (millis() - lastStatusUpdate > 10000) { + lastStatusUpdate = millis(); + updateSensorStatus(); + } + + if (!isTesting) { + handleRFIDScan(); + } + } +} diff --git a/firmware/test_rfid_gain.ino b/firmware/test_rfid_gain.ino new file mode 100644 index 0000000..ad8e666 --- /dev/null +++ b/firmware/test_rfid_gain.ino @@ -0,0 +1,59 @@ +#include +#include + +#define SS_PIN 21 +#define RST_PIN 22 + +MFRC522 rfid(SS_PIN, RST_PIN); + +void setup() { + Serial.begin(115200); + delay(1000); + SPI.begin(); + rfid.PCD_Init(); + + Serial.println("\n\n========================================="); + Serial.println(" TEST RESPONSIVITAS & GAIN ANTENA RFID "); + Serial.println("========================================="); + Serial.println("Cara Pakai: Dekatkan kartu dari jarak jauh ke dekat."); + Serial.println("Ketik angka (0-5) di Serial Monitor lalu Enter untuk mengubah Gain:"); + Serial.println("0 = 18 dB (Paling Lemah)"); + Serial.println("1 = 23 dB"); + Serial.println("2 = 33 dB (Default)"); + Serial.println("3 = 38 dB"); + Serial.println("4 = 43 dB"); + Serial.println("5 = 48 dB (Maksimal)"); + Serial.println("=========================================\n"); + + rfid.PCD_SetAntennaGain(rfid.RxGain_33dB); + Serial.println("-> Mode Awal Aktif: 2 (33 dB - Default)"); +} + +void loop() { + // Cek input angka dari Serial Monitor + if (Serial.available() > 0) { + char inChar = Serial.read(); + if (inChar == '0') { rfid.PCD_SetAntennaGain(rfid.RxGain_18dB); Serial.println("\n>> Gain diubah ke 0 (18 dB)"); } + else if (inChar == '1') { rfid.PCD_SetAntennaGain(rfid.RxGain_23dB); Serial.println("\n>> Gain diubah ke 1 (23 dB)"); } + else if (inChar == '2') { rfid.PCD_SetAntennaGain(rfid.RxGain_33dB); Serial.println("\n>> Gain diubah ke 2 (33 dB - Default)"); } + else if (inChar == '3') { rfid.PCD_SetAntennaGain(rfid.RxGain_38dB); Serial.println("\n>> Gain diubah ke 3 (38 dB)"); } + else if (inChar == '4') { rfid.PCD_SetAntennaGain(rfid.RxGain_43dB); Serial.println("\n>> Gain diubah ke 4 (43 dB)"); } + else if (inChar == '5') { rfid.PCD_SetAntennaGain(rfid.RxGain_max); Serial.println("\n>> Gain diubah ke 5 (48 dB - Maksimal)"); } + } + + // Cek RFID (Tanpa ada delay atau WiFi yang menghambat) + if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { + Serial.print("💳 Kartu Terdeteksi! UID: "); + for (byte i = 0; i < rfid.uid.size; i++) { + if (rfid.uid.uidByte[i] < 0x10) Serial.print("0"); + Serial.print(rfid.uid.uidByte[i], HEX); + } + Serial.println(" (Responsif & Lancar!)"); + + // Jeda sedikit agar layar tidak terlalu penuh teks saat kartu ditempel + delay(200); + + rfid.PICC_HaltA(); + rfid.PCD_StopCrypto1(); + } +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..18bc70e --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,16 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/frontend/error-log.txt b/frontend/error-log.txt new file mode 100644 index 0000000000000000000000000000000000000000..42b7bc4a6569f2aa8c434acd61fb8391be213dca GIT binary patch literal 738 zcmaKqy-LJD6on7i2|j_%^rHL6x@-!uu@J;cY^+2hS&XhEaaW(iN3ifM)$h(^%9Ze9J5aD z`zb$mzT9UIgOOj*jXNmHL?!c-vCd}``iE`&?l)rAeX$=4X literal 0 HcmV?d00001 diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..4fa125d --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..899c65a --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + ImpactMonitor - Atlet IoT + + +
+ + + diff --git a/frontend/jsconfig.json b/frontend/jsconfig.json new file mode 100644 index 0000000..3255bae --- /dev/null +++ b/frontend/jsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + } +} \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..6a58473 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,6289 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@tailwindcss/postcss": "^4.1.18", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "firebase": "^12.11.0", + "jiti": "^2.6.1", + "jspdf": "^4.2.0", + "jspdf-autotable": "^5.0.7", + "lucide-react": "^0.563.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.13.0", + "recharts": "^3.8.1", + "socket.io-client": "^4.8.3", + "tailwind-merge": "^3.4.0", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "autoprefixer": "^10.4.24", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", + "vite": "^7.3.1" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@firebase/ai": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.10.0.tgz", + "integrity": "sha512-1lI6HomyoO/8RSJb6ItyHLpHnB2z27m5F4aX/Vpi1nhwWoxdNjkq+6UQOykHyCE0KairojOE5qQ20i1tnF0nNA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.21", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.21.tgz", + "integrity": "sha512-j2y2q65BlgLGB5Pwjhv/Jopw2X/TBTzvAtI5z/DSp56U4wBj7LfhBfzbdCtFPges+Wz0g55GdoawXibOH5jGng==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.27.tgz", + "integrity": "sha512-ZObpYpAxL6JfgH7GnvlDD0sbzGZ0o4nijV8skatV9ZX49hJtCYbFqaEcPYptT94rgX1KUoKEderC7/fa7hybtw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.21", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz", + "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.10.tgz", + "integrity": "sha512-PlPhdtjgWUra+LImQTnXOUqUa/jcufZhizdR93ZjlQSS3ahCtDTG6pJw7j0OwFal18DQjICXfeVNsUUrcNisfA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.2.tgz", + "integrity": "sha512-jcXQVMHAQ5AEKzVD5C7s5fmAYeFOuN6lAJeNTgZK2B9aLnofWaJt8u1A8Idm8gpsBBYSaY3cVyeH5SWMOVPBLQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.2.tgz", + "integrity": "sha512-M91NhxqbSkI0ChkJWy69blC+rPr6HEgaeRllddSaU1pQ/7IiegeCQM9pPDIgvWnwnBSzKhUHpe6ro/jhJ+cvzw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.11.2", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz", + "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.10.tgz", + "integrity": "sha512-tFmBuZL0/v1h6eyKRgWI58ucft6dEJmAi9nhPUXoAW4ZbPSTlnsh31AuEwUoRTz+wwRk9gmgss9GZV05ZM9Kug==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.14.10", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.12.2.tgz", + "integrity": "sha512-CZJL8V10Vzibs+pDTXdQF+hot1IigIoqF4a4lA/qr5Deo1srcefiyIfgg28B67Lk7IxZhwfJMuI+1bu2xBmV0A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^2.2.0" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.4.tgz", + "integrity": "sha512-2pj8m/hnqXvMLfC0Mk+fORVTM5DQPkS6l8JpMgtoAWGVgCmYnoWdFMaNWtKbmCxBEyvMA3FlnCJyzrUSMWTfuA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.12.2", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", + "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.2.tgz", + "integrity": "sha512-iyVDGc6Vjx7Rm0cAdccLH/NG6fADsgJak/XW9IA2lPf8AjIlsemOpFGKczYyPHxm4rnKdR8z6sK4+KEC7NwmEg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.5.0.tgz", + "integrity": "sha512-G3GYHpWNJJ95502RQLApzw0jaG3pScHl+J/2MdxIuB51xtHnkRL6KvIAP3fFF1drUewWJHOnDA1U+q4Evf3KSw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.2.tgz", + "integrity": "sha512-lP96CMjMPy/+d1d9qaaHjHHdzdwvEOuyyLq9ehX89e2XMKwS1jHNzYBO+42bdSumuj5ukPbmnFtViZu8YOMT+w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.2.tgz", + "integrity": "sha512-j4A6IhVZbgxAzT6gJJC2PfOxYCK9SrDrUO7nTM4EscTYtKkAkzsbKoCnDdjFapQfnsncvPWjqVTr/0PffUwg3g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/database": "1.1.2", + "@firebase/database-types": "1.0.18", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.18.tgz", + "integrity": "sha512-yOY8IC2go9lfbVDMiy2ATun4EB2AFwocPaQADwMN/RHRUAZSM4rlAV7PGbWPSG/YhkJ2A9xQAiAENgSua9G5Fg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.15.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.13.0.tgz", + "integrity": "sha512-7i4cVNJXTMim7/P7UsNim0DwyLPk4QQ3y1oSNzv4l0ykJOKYCiFMOuEeUxUYvrReXDJxWHrT/4XMeVQm+13rRw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "@firebase/webchannel-wrapper": "1.0.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.7.tgz", + "integrity": "sha512-Et4XxtGnjp0Q9tmaEMETnY5GHJ8gQ9+RN6sSTT4ETWKmym2d6gIjarw0rCQcx+7BrWVYLEIOAXSXysl0b3xnUA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/firestore": "4.13.0", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz", + "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.3.tgz", + "integrity": "sha512-csO7ckK3SSs+NUZW1nms9EK7ckHe/1QOjiP8uAkCYa7ND18s44vjE9g3KxEeIUpyEPqZaX1EhJuFyZjHigAcYw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.3.tgz", + "integrity": "sha512-BxkEwWgx1of0tKaao/r2VR6WBLk/RAiyztatiONPrPE8gkitFkOnOCxf8i9cUyA5hX5RGt5H30uNn25Q6QNEmQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/functions": "0.13.3", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz", + "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.21", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.21.tgz", + "integrity": "sha512-xGFGTeICJZ5vhrmmDukeczIcFULFXybojML2+QSDFoKj5A7zbGN7KzFGSKNhDkIxpjzsYG9IleJyUebuAcmqWA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.21.tgz", + "integrity": "sha512-zahIUkaVKbR8zmTeBHkdfaVl6JGWlhVoSjF7CVH33nFqD3SlPEpEEegn2GNT5iAfsVdtlCyJJ9GW4YKjq+RJKQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz", + "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz", + "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.25.tgz", + "integrity": "sha512-7RhDwoDHlOK1/ou0/LeubxmjcngsTjDdrY/ssg2vwAVpUuVAhQzQvuCAOYxcX5wNC1zCgQ54AP1vdngBwbCmOQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.25.tgz", + "integrity": "sha512-eoOQqGLtRlseTdiemTN44LlHZpltK5gnhq8XVUuLgtIOG+odtDzrz2UoTpcJWSzaJQVxNLb/x9f39tHdDM4N4w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/messaging": "0.12.25", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz", + "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.11.tgz", + "integrity": "sha512-V3uAhrz7IYJuji+OgT3qYTGKxpek/TViXti9OSsUJ4AexZ3jQjYH5Yrn7JvBxk8MGiSLsC872hh+BxQiPZsm7g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.24", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.24.tgz", + "integrity": "sha512-YRlejH8wLt7ThWao+HXoKUHUrZKGYq+otxkPS+8nuE5PeN1cBXX7NAJl9ueuUkBwMIrnKdnDqL/voHXxDAAt3g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/performance": "0.7.11", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz", + "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.8.2.tgz", + "integrity": "sha512-5EXqOThV4upjK9D38d/qOSVwOqRhemlaOFk9vCkMNNALeIlwr+4pLjtLNo4qoY8etQmU/1q4aIATE9N8PFqg0g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.23.tgz", + "integrity": "sha512-4+KqRRHEUUmKT6tFmnpWATOsaFfmSuBs1jXH8JzVtMLEYqq/WS9IDM92OdefFDSrAA2xGd0WN004z8mKeIIscw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-types": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz", + "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.2.tgz", + "integrity": "sha512-o/culaTeJ8GRpKXRJov21rux/n9dRaSOWLebyatFP2sqEdCxQPjVA1H9Z2fzYwQxMIU0JVmC7SPPmU11v7L6vQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.2.tgz", + "integrity": "sha512-R+aB38wxCH5zjIO/xu9KznI7fgiPuZAG98uVm1NcidHyyupGgIDLKigGmRGBZMnxibe/m2oxNKoZpfEbUX2aQQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/storage": "0.14.2", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz", + "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.15.0.tgz", + "integrity": "sha512-AmWf3cHAOMbrCPG4xdPKQaj5iHnyYfyLKZxwz+Xf55bqKbpAmcYifB4jQinT2W9XhDRHISOoPyBOariJpCG6FA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz", + "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==", + "license": "Apache-2.0" + }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", + "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "postcss": "^8.4.41", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", + "license": "MIT" + }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", + "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.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, + "license": "MIT" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvg": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz", + "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/core-js": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/dompurify": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", + "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-toolkit": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-png": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz", + "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==", + "license": "MIT", + "dependencies": { + "@types/pako": "^2.0.3", + "iobuffer": "^5.3.2", + "pako": "^2.1.0" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/firebase": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.11.0.tgz", + "integrity": "sha512-W9f3Y+cgQYgF9gvCGxt0upec8zwAtiQVcHuU8MfzUIgVU/9fRQWtu48Geiv1lsigtBz9QHML++Km9xAKO5GB5Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/ai": "2.10.0", + "@firebase/analytics": "0.10.21", + "@firebase/analytics-compat": "0.2.27", + "@firebase/app": "0.14.10", + "@firebase/app-check": "0.11.2", + "@firebase/app-check-compat": "0.4.2", + "@firebase/app-compat": "0.5.10", + "@firebase/app-types": "0.9.3", + "@firebase/auth": "1.12.2", + "@firebase/auth-compat": "0.6.4", + "@firebase/data-connect": "0.5.0", + "@firebase/database": "1.1.2", + "@firebase/database-compat": "2.1.2", + "@firebase/firestore": "4.13.0", + "@firebase/firestore-compat": "0.4.7", + "@firebase/functions": "0.13.3", + "@firebase/functions-compat": "0.4.3", + "@firebase/installations": "0.6.21", + "@firebase/installations-compat": "0.2.21", + "@firebase/messaging": "0.12.25", + "@firebase/messaging-compat": "0.2.25", + "@firebase/performance": "0.7.11", + "@firebase/performance-compat": "0.2.24", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-compat": "0.2.23", + "@firebase/storage": "0.14.2", + "@firebase/storage-compat": "0.4.2", + "@firebase/util": "1.15.0" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/iobuffer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", + "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==", + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jspdf": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.2.0.tgz", + "integrity": "sha512-hR/hnRevAXXlrjeqU5oahOE+Ln9ORJUB5brLHHqH67A+RBQZuFr5GkbI9XQI8OUFSEezKegsi45QRpc4bGj75Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.6", + "fast-png": "^6.2.0", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.11", + "core-js": "^3.6.0", + "dompurify": "^3.3.1", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf-autotable": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.7.tgz", + "integrity": "sha512-2wr7H6liNDBYNwt25hMQwXkEWFOEopgKIvR1Eukuw6Zmprm/ZcnmLTQEjW7Xx3FCbD3v7pflLcnMAv/h1jFDQw==", + "license": "MIT", + "peerDependencies": { + "jspdf": "^2 || ^3 || ^4" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.563.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz", + "integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz", + "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", + "license": "MIT", + "peer": true + }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", + "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/recharts": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz", + "integrity": "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "license": "MIT" + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..c1e88bc --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,48 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@tailwindcss/postcss": "^4.1.18", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "firebase": "^12.11.0", + "jiti": "^2.6.1", + "jspdf": "^4.2.0", + "jspdf-autotable": "^5.0.7", + "lucide-react": "^0.563.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.13.0", + "recharts": "^3.8.1", + "socket.io-client": "^4.8.3", + "tailwind-merge": "^3.4.0", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "autoprefixer": "^10.4.24", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", + "vite": "^7.3.1" + } +} diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..48dab30 --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + "@tailwindcss/postcss": {}, + autoprefixer: {}, + }, +} diff --git a/frontend/public/logo.png b/frontend/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..143b10d91f8cf1c741717dd368bc868a815d93bd GIT binary patch literal 113566 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

>wh>8zte~8FL|GK%__Dv#**gkY+(t= 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 KMNUMnLSTYoM|oNR literal 0 HcmV?d00001 diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/App.css b/frontend/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/frontend/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 0000000..ab17a0e --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,119 @@ +import React from 'react'; +import { BrowserRouter, Routes, Route, Outlet, Link, useLocation, useNavigate } from 'react-router-dom'; +import { AuthProvider } from './context/AuthContext'; +import { useAuth } from './context/AuthContext'; +import ProtectedRoute from './components/ProtectedRoute'; + +import AdminLogin from './pages/AdminLogin'; +import Register from './pages/Register'; +import Monitor from './pages/Monitor'; +import Dashboard from './pages/Dashboard'; +import Leaderboard from './pages/Leaderboard'; +import Settings from './pages/Settings'; +import LiveTest from './pages/LiveTest'; +import { Activity, UserPlus, Trophy, LayoutDashboard, Monitor as MonitorIcon, LogOut, Settings as SettingsIcon } from 'lucide-react'; +import { cn } from './lib/utils'; +import { Button } from './components/ui/button'; + +const NavLink = ({ to, icon: Icon, label }) => { + const { pathname } = useLocation(); + const isActive = pathname === to || (to !== '/' && pathname.startsWith(to)); + return ( + + + {label} + {isActive && ( + + )} + + ); +}; + +const AdminLayout = () => { + const { logout } = useAuth(); + const navigate = useNavigate(); + + const handleLogout = () => { + logout(); + navigate('/login'); + }; + + return ( +

+ +
+
+ +
+
+
+

© {new Date().getFullYear()} ImpactMonitor Pro · Dirancang untuk Atlet Profesional

+
+
+ ); +}; + +function App() { + return ( + + + + } /> + + }> + }> + } /> + } /> + } /> + } /> + } /> + } /> + + + + + + ); +} + +export default App; diff --git a/frontend/src/api/api.js b/frontend/src/api/api.js new file mode 100644 index 0000000..a2185fd --- /dev/null +++ b/frontend/src/api/api.js @@ -0,0 +1,41 @@ +const API_URL = import.meta.env.VITE_API_URL ? `${import.meta.env.VITE_API_URL}/api` : 'http://localhost:3000/api'; + +export const getAthletes = async () => { + const res = await fetch(`${API_URL}/athletes`); + return res.json(); +}; + +export const getAthlete = async (id) => { + const res = await fetch(`${API_URL}/athletes/${id}`); + if (!res.ok) throw new Error('Failed to fetch athlete'); + return res.json(); +}; + +export const registerAthlete = async (data) => { + const res = await fetch(`${API_URL}/athletes`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + if (!res.ok) throw new Error('Registration failed'); + return res.json(); +}; + +export const getLeaderboard = async () => { + const res = await fetch(`${API_URL}/leaderboard`); + return res.json(); +}; + +export const startTest = async (athleteId) => { + const res = await fetch(`${API_URL}/start-test`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ athleteId }), + }); + return res.json(); +}; + +export const stopTest = async () => { + const res = await fetch(`${API_URL}/stop-test`, { method: 'POST' }); + return res.json(); +}; diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/frontend/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/components/HistoryModal.jsx b/frontend/src/components/HistoryModal.jsx new file mode 100644 index 0000000..9cbb51d --- /dev/null +++ b/frontend/src/components/HistoryModal.jsx @@ -0,0 +1,232 @@ +import React, { useState, useEffect } from 'react'; +import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; +import { rtdb } from '../firebase'; +import { ref, get } from 'firebase/database'; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { TrendingUp, Calendar, Zap, Target } from 'lucide-react'; + +const HistoryModal = ({ athlete, isOpen, onClose }) => { + const [history, setHistory] = useState([]); + const [loading, setLoading] = useState(true); + const [debugKeys, setDebugKeys] = useState([]); + + useEffect(() => { + if (!isOpen || !athlete) return; + + setLoading(true); + setDebugKeys(["Mencari..."]); + + const possibleIds = new Set([ + athlete.id, + athlete.id?.toLowerCase(), + athlete.id?.toUpperCase(), + athlete.rfid_tag, + athlete.rfid_tag?.toLowerCase(), + athlete.rfid_tag?.toUpperCase() + ].filter(Boolean)); + + const paths = []; + possibleIds.forEach(id => { + paths.push(`test_history/${id}`); + paths.push(`attempts/${id}`); + }); + + const checkPaths = async () => { + let finalData = null; + + for (const path of paths) { + try { + const historyRef = ref(rtdb, path); + const snapshot = await get(historyRef); + const data = snapshot.val(); + if (data) { + finalData = data; + setDebugKeys(Object.keys(data)); + break; // Berhenti jika sudah ketemu data yang valid + } + } catch (err) { + setDebugKeys(["Error: " + err.message]); + } + } + + if (finalData) { + const attemptArray = []; + + // Cek apakah data bersarang (Session -> Attempt) atau langsung Attempt + Object.keys(finalData).forEach(sessionKey => { + const sessionData = finalData[sessionKey]; + + if (sessionKey.startsWith('session_') && typeof sessionData === 'object') { + // Ambil timestamp dari nama folder session (format: session_177xxxxxxxxx) + const sessionTimestamp = parseInt(sessionKey.replace('session_', '')); + + // Cari nilai tertinggi dalam sesi ini (dari attempt_1, 2, 3) + let sessionMax = 0; + let sessionMaxType = ''; + + Object.keys(sessionData).forEach(attemptKey => { + if (attemptKey.startsWith('attempt_')) { + const item = sessionData[attemptKey]; + const score = item.peak_newton || item.force || 0; + if (Number(score) > sessionMax) { + sessionMax = Number(score); + sessionMaxType = item.type || 'pukulan'; + } + } + }); + + if (sessionMax > 0) { + const ts = (sessionTimestamp > 1000000) ? sessionTimestamp : Date.now(); + const typeLabel = sessionMaxType.charAt(0).toUpperCase() + sessionMaxType.slice(1); + + attemptArray.push({ + date: new Date(ts).toLocaleDateString('id-ID', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' }), + force: Number(sessionMax.toFixed(1)), + timestamp: ts, + label: `${typeLabel} Peak - ${new Date(ts).toLocaleDateString('id-ID', { hour: '2-digit', minute: '2-digit' })}` + }); + } + } else if (sessionKey.startsWith('attempt_')) { + // Jika struktur langsung (Legacy/Lama) + const item = sessionData; + const score = item.peak_newton || item.force || 0; + const ts = (item.timestamp > 1000000) ? item.timestamp : Date.now(); + + attemptArray.push({ + date: new Date(ts).toLocaleDateString('id-ID', { day: '2-digit', month: 'short' }), + force: Number(Number(score).toFixed(1)), + timestamp: ts, + label: `Legacy Test #${sessionKey.replace('attempt_', '')}` + }); + } + }); + + if (attemptArray.length > 0) { + const sorted = attemptArray.sort((a, b) => a.timestamp - b.timestamp); + setHistory(sorted); + } else { + setHistory([]); + } + } else { + setHistory([]); + setDebugKeys(["ID Tidak Ditemukan"]); + } + setLoading(false); + }; + + checkPaths(); + }, [isOpen, athlete]); + + const maxPower = history.length > 0 ? Math.max(...history.map(d => d.force)) : 0; + const avgPower = history.length > 0 ? (history.reduce((acc, curr) => acc + curr.force, 0) / history.length).toFixed(1) : 0; + + return ( + + + + + + Riwayat Performa: {athlete?.name} + + + Grafik perkembangan kekuatan atlet berdasarkan data latihan yang tercatat. + + + +
+
+
+ Max Power +
+
{maxPower} N
+
+
+
+ Avg Power +
+
{avgPower} N
+
+
+
+ Total Sesi +
+
{history.length} Kali
+
+
+ +
+ {loading ? ( +
+ Memuat data grafik... +
+ ) : history.length > 0 ? ( + + + + + + + + + + val.split(' ')[0]} + /> + `${val}N`} + /> + { + if (active && payload && payload.length) { + const data = payload[0].payload; + return ( +
+

{data.label}

+

{data.force} Newton

+
+ ); + } + return null; + }} + /> + +
+
+ ) : ( +
+ + Belum ada data riwayat untuk atlet ini. +
+
Debug Info:
+
• Target ID: {athlete?.id}
+
• Items Found: {history.length}
+
• Folder Keys: {debugKeys.join(', ')}
+
• DB URL: {rtdb.app.options.databaseURL}
+
+ Jika "Items Found" adalah 0 padahal di Firebase ada, kemungkinan struktur data di dalam folder ID tidak sesuai standar (attempt_N). +
+
+
+ )} +
+
+
+ ); +}; + +export default HistoryModal; diff --git a/frontend/src/components/ProtectedRoute.jsx b/frontend/src/components/ProtectedRoute.jsx new file mode 100644 index 0000000..a22e35e --- /dev/null +++ b/frontend/src/components/ProtectedRoute.jsx @@ -0,0 +1,12 @@ +import { Navigate, Outlet } from "react-router-dom"; +import { useAuth } from "@/context/AuthContext"; + +const ProtectedRoute = () => { + const { user } = useAuth(); + if (!user) { + return ; + } + return ; +}; + +export default ProtectedRoute; diff --git a/frontend/src/components/ui/badge.jsx b/frontend/src/components/ui/badge.jsx new file mode 100644 index 0000000..9f071b8 --- /dev/null +++ b/frontend/src/components/ui/badge.jsx @@ -0,0 +1,31 @@ +import * as React from "react" +import { cva } from "class-variance-authority" +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ className, variant, ...props }) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/frontend/src/components/ui/button.jsx b/frontend/src/components/ui/button.jsx new file mode 100644 index 0000000..9543d63 --- /dev/null +++ b/frontend/src/components/ui/button.jsx @@ -0,0 +1,47 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva } from "class-variance-authority" +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) +}) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/frontend/src/components/ui/card.jsx b/frontend/src/components/ui/card.jsx new file mode 100644 index 0000000..b2c196e --- /dev/null +++ b/frontend/src/components/ui/card.jsx @@ -0,0 +1,57 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +const Card = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/frontend/src/components/ui/dialog.jsx b/frontend/src/components/ui/dialog.jsx new file mode 100644 index 0000000..57fa8a1 --- /dev/null +++ b/frontend/src/components/ui/dialog.jsx @@ -0,0 +1,89 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root +const DialogTrigger = DialogPrimitive.Trigger +const DialogPortal = DialogPrimitive.Portal +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ className, ...props }) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/frontend/src/components/ui/input.jsx b/frontend/src/components/ui/input.jsx new file mode 100644 index 0000000..ff2b1c0 --- /dev/null +++ b/frontend/src/components/ui/input.jsx @@ -0,0 +1,19 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +const Input = React.forwardRef(({ className, type, ...props }, ref) => { + return ( + + ) +}) +Input.displayName = "Input" + +export { Input } diff --git a/frontend/src/components/ui/label.jsx b/frontend/src/components/ui/label.jsx new file mode 100644 index 0000000..ec7a7f8 --- /dev/null +++ b/frontend/src/components/ui/label.jsx @@ -0,0 +1,19 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva } from "class-variance-authority" +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/frontend/src/components/ui/select.jsx b/frontend/src/components/ui/select.jsx new file mode 100644 index 0000000..1ee7552 --- /dev/null +++ b/frontend/src/components/ui/select.jsx @@ -0,0 +1,137 @@ +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { Check, ChevronDown, ChevronUp } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/frontend/src/components/ui/separator.jsx b/frontend/src/components/ui/separator.jsx new file mode 100644 index 0000000..129ce6d --- /dev/null +++ b/frontend/src/components/ui/separator.jsx @@ -0,0 +1,25 @@ +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" +import { cn } from "@/lib/utils" + +const Separator = React.forwardRef( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/frontend/src/components/ui/table.jsx b/frontend/src/components/ui/table.jsx new file mode 100644 index 0000000..0a6c0d6 --- /dev/null +++ b/frontend/src/components/ui/table.jsx @@ -0,0 +1,92 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +const Table = React.forwardRef(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/frontend/src/context/AuthContext.jsx b/frontend/src/context/AuthContext.jsx new file mode 100644 index 0000000..5f37fc3 --- /dev/null +++ b/frontend/src/context/AuthContext.jsx @@ -0,0 +1,52 @@ +import { createContext, useContext, useState, useEffect } from "react"; + +const AuthContext = createContext(); + +export const useAuth = () => useContext(AuthContext); + +export const AuthProvider = ({ children }) => { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Check session storage for existing session + const token = sessionStorage.getItem("adminToken"); + const username = sessionStorage.getItem("adminUsername"); + if (token) { + setUser({ role: "admin", username: username }); + } + setLoading(false); + }, []); + + const login = async (username, password) => { + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const response = await fetch(`${API_URL}/api/admin/login`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username, password }), + }); + const data = await response.json(); + if (data.success) { + sessionStorage.setItem("adminToken", data.token); + sessionStorage.setItem("adminUsername", data.username); + setUser({ role: "admin", username: data.username }); + return { success: true }; + } + return { success: false, message: data.message }; + } catch (error) { + return { success: false, message: "Login failed" }; + } + }; + + const logout = () => { + sessionStorage.removeItem("adminToken"); + setUser(null); + }; + + return ( + + {!loading && children} + + ); +}; diff --git a/frontend/src/context/SocketContext.jsx b/frontend/src/context/SocketContext.jsx new file mode 100644 index 0000000..0a9d99c --- /dev/null +++ b/frontend/src/context/SocketContext.jsx @@ -0,0 +1,34 @@ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { io } from 'socket.io-client'; + +const SocketContext = createContext(); + +export const useSocket = () => { + const context = useContext(SocketContext); + if (context === undefined) { + throw new Error('useSocket must be used within a SocketProvider'); + } + return context; +}; + +export const SocketProvider = ({ children }) => { + const [socket, setSocket] = useState(null); + + useEffect(() => { + const SOCKET_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const newSocket = io(SOCKET_URL); + setSocket(newSocket); + + newSocket.on('connect', () => { + console.log('Connected to backend socket'); + }); + + return () => newSocket.close(); + }, []); + + return ( + + {children} + + ); +}; diff --git a/frontend/src/firebase.js b/frontend/src/firebase.js new file mode 100644 index 0000000..e858b21 --- /dev/null +++ b/frontend/src/firebase.js @@ -0,0 +1,17 @@ +import { initializeApp } from "firebase/app"; +import { getDatabase } from "firebase/database"; + +const firebaseConfig = { + apiKey: "AIzaSyDhFtqvaTMgYH9vyAHFclDUXiOxkl-2GqM", + authDomain: "silat-b3100.firebaseapp.com", + databaseURL: "https://silat-b3100-default-rtdb.firebaseio.com/", + projectId: "silat-b3100", + storageBucket: "silat-b3100.firebasestorage.app", + messagingSenderId: "471266034969", + appId: "1:471266034969:web:467de19582cf2fd3da3188" +}; + +const app = initializeApp(firebaseConfig); +const rtdb = getDatabase(app); + +export { rtdb }; \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..12b8cfe --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,167 @@ +@import "tailwindcss"; + +@plugin "tailwindcss-animate"; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + + --radius-lg: var(--radius); + --radius-md: calc(var(--radius) - 2px); + --radius-sm: calc(var(--radius) - 4px); + + --color-background: hsl(var(--background)); + --color-foreground: hsl(var(--foreground)); + + --color-card: hsl(var(--card)); + --color-card-foreground: hsl(var(--card-foreground)); + + --color-popover: hsl(var(--popover)); + --color-popover-foreground: hsl(var(--popover-foreground)); + + --color-primary: hsl(var(--primary)); + --color-primary-foreground: hsl(var(--primary-foreground)); + + --color-secondary: hsl(var(--secondary)); + --color-secondary-foreground: hsl(var(--secondary-foreground)); + + --color-muted: hsl(var(--muted)); + --color-muted-foreground: hsl(var(--muted-foreground)); + + --color-accent: hsl(var(--accent)); + --color-accent-foreground: hsl(var(--accent-foreground)); + + --color-destructive: hsl(var(--destructive)); + --color-destructive-foreground: hsl(var(--destructive-foreground)); + + --color-border: hsl(var(--border)); + --color-input: hsl(var(--input)); + --color-ring: hsl(var(--ring)); + + --color-chart-1: hsl(var(--chart-1)); + --color-chart-2: hsl(var(--chart-2)); + --color-chart-3: hsl(var(--chart-3)); + --color-chart-4: hsl(var(--chart-4)); + --color-chart-5: hsl(var(--chart-5)); +} + +@layer base { + :root { + --background: 210 40% 98%; + --foreground: 222.2 47.4% 11.2%; + + --card: 0 0% 100%; + --card-foreground: 222.2 47.4% 11.2%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 47.4% 11.2%; + + --primary: 221.2 83.2% 53.3%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 221.2 83.2% 53.3%; + + --radius: 1rem; + + --chart-1: 221 83% 53%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 217.2 91.2% 59.8%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 224.3 76.3% 48%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground font-sans antialiased; + background-image: + radial-gradient(circle at top right, rgba(59, 130, 246, 0.08) 0%, transparent 40%), + radial-gradient(circle at bottom left, rgba(16, 185, 129, 0.05) 0%, transparent 40%), + linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.4)); + background-attachment: fixed; + } +} + +@layer utilities { + .glass-card { + @apply bg-white/70 backdrop-blur-xl border border-white/20 shadow-xl shadow-primary/5; + } + + .glass-card-dark { + @apply bg-slate-950/40 backdrop-blur-xl border border-slate-800/50 shadow-2xl; + } + + .text-gradient { + @apply bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-600; + } + + .tech-grid { + background-size: 40px 40px; + background-image: + linear-gradient(to right, rgba(0, 0, 0, 0.02) 1px, transparent 1px), + linear-gradient(to bottom, rgba(0, 0, 0, 0.02) 1px, transparent 1px); + } +} + +/* Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Firefox */ +input[type=number] { + -moz-appearance: textfield; +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-track { + @apply bg-transparent; +} +::-webkit-scrollbar-thumb { + @apply bg-slate-200 rounded-full hover:bg-slate-300 transition-colors; +} \ No newline at end of file diff --git a/frontend/src/lib/utils.js b/frontend/src/lib/utils.js new file mode 100644 index 0000000..ea399f7 --- /dev/null +++ b/frontend/src/lib/utils.js @@ -0,0 +1,6 @@ +import { clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs) { + return twMerge(clsx(inputs)) +} diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/frontend/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/frontend/src/pages/AdminLogin.jsx b/frontend/src/pages/AdminLogin.jsx new file mode 100644 index 0000000..398652d --- /dev/null +++ b/frontend/src/pages/AdminLogin.jsx @@ -0,0 +1,116 @@ +import { useState, useEffect } from "react"; +import { useAuth } from "@/context/AuthContext"; +import { useNavigate } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Activity, Lock } from "lucide-react"; + +const AdminLogin = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const { login, user } = useAuth(); + const navigate = useNavigate(); + + // Jika sudah login, langsung lempar ke dashboard + useEffect(() => { + if (user) { + navigate("/"); + } + }, [user, navigate]); + + const handleSubmit = async (e) => { + e.preventDefault(); + setIsLoading(true); + const result = await login(username, password); + setIsLoading(false); + if (result.success) { + navigate("/"); + } else { + setError(result.message); + } + }; + + return ( +
+ {/* Decorative background blobs */} +
+
+ +
+ {/* Branding */} +
+
+ IKSPI +
+

+ IMPACTMONITOR +

+

Sistem Monitoring Atlet Silat Pro Edition

+
+ + + + +
+ +
+ Login Admin +
+ Silakan masukkan kata sandi untuk mengelola data atlet. +
+
+ +
+ + setUsername(e.target.value)} + className="h-12 bg-white/50 border-slate-200 focus:ring-2 focus:ring-primary/20 transition-all text-lg" + /> +
+
+ + setPassword(e.target.value)} + className="h-12 bg-white/50 border-slate-200 focus:ring-2 focus:ring-primary/20 transition-all text-lg" + /> +
+ {error && ( +

+ + {error} +

+ )} +
+ + + +
+
+ +

+ © {new Date().getFullYear()} ImpactMonitor Pro · Dirancang untuk IKSPI Kera Sakti +

+
+
+ ); +}; + +export default AdminLogin; diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx new file mode 100644 index 0000000..c67a1d8 --- /dev/null +++ b/frontend/src/pages/Dashboard.jsx @@ -0,0 +1,376 @@ +import React, { useEffect, useState } from 'react'; +import { Link } from 'react-router-dom'; + +import { User, Activity, Trash2, UserPlus, Users, Zap, TrendingUp, Info, History } from 'lucide-react'; +import HistoryModal from '../components/HistoryModal'; +import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardDescription } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Separator } from "@/components/ui/separator"; +import { cn } from "@/lib/utils"; +import { rtdb } from "../firebase"; +import { ref, onValue, remove } from "firebase/database"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, + DialogClose, +} from "@/components/ui/dialog"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; + +const CATEGORIES = ["Usia dini A", "Usia dini B", "Pra remaja", "Remaja", "Dewasa"]; + +const StatCard = ({ title, value, icon: Icon, color }) => ( + + +
+
+

{title}

+

{value}

+
+
+ +
+
+
+
+); + +const Dashboard = () => { + const [athletes, setAthletes] = useState([]); + const [serverStatus, setServerStatus] = useState('Menghubungkan...'); + const [sensorStatus, setSensorStatus] = useState('Memeriksa...'); + const [serverColor, setServerColor] = useState('text-slate-400 bg-slate-50'); + const [sensorColor, setSensorColor] = useState('text-slate-400 bg-slate-50'); + + const [selectedAthlete, setSelectedAthlete] = useState(null); + const [isHistoryOpen, setIsHistoryOpen] = useState(false); + const [categoryFilter, setCategoryFilter] = useState('all'); + + // Cek status App Server (Node.js backend) via HTTP ping setiap 4 detik + // Lebih cepat dari Socket.IO ping timeout (20-30 detik) + useEffect(() => { + let pingInterval = null; + + const checkServer = async () => { + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const res = await fetch(`${API_URL}/api/athletes`, { + signal: AbortSignal.timeout(2000) // timeout 2 detik + }); + if (res.ok || res.status < 500) { + setServerStatus('Online'); + setServerColor('text-emerald-600 bg-emerald-50'); + } else { + setServerStatus('Error'); + setServerColor('text-orange-500 bg-orange-50'); + } + } catch { + setServerStatus('Offline'); + setServerColor('text-red-500 bg-red-50'); + } + }; + + // Cek langsung saat komponen mount + checkServer(); + // Lalu cek setiap 4 detik + pingInterval = setInterval(checkServer, 4000); + + return () => clearInterval(pingInterval); + }, []); + + + // Cek status sensor IoT dari Firebase RTDB (timestamp heartbeat) + // Firmware menulis Unix timestamp ke /system/last_seen setiap 8 detik + // Dashboard cek apakah timestamp sudah >15 detik → Offline + useEffect(() => { + const lastSeenRef = ref(rtdb, '/system/last_seen'); + let lastSeenValue = 0; + let checkInterval = null; + + const unsubscribe = onValue(lastSeenRef, (snapshot) => { + const ts = snapshot.val(); + if (ts && ts > 0) { + lastSeenValue = ts; // Unix timestamp dari firmware + } + }); + + // Cek staleness setiap 5 detik + checkInterval = setInterval(() => { + if (lastSeenValue === 0) { + setSensorStatus('Tidak Terdeteksi'); + setSensorColor('text-slate-400 bg-slate-50'); + return; + } + const nowSec = Math.floor(Date.now() / 1000); + const ageSeconds = nowSec - lastSeenValue; + + if (ageSeconds <= 15) { + // Heartbeat masih segar → Online + setSensorStatus('Online'); + setSensorColor('text-emerald-600 bg-emerald-50'); + } else { + // Heartbeat sudah lama → alat mati/putus + setSensorStatus('Offline'); + setSensorColor('text-red-500 bg-red-50'); + } + }, 5000); + + return () => { + unsubscribe(); + clearInterval(checkInterval); + }; + }, []); + + + + + + useEffect(() => { + const usersRef = ref(rtdb, 'users'); + const unsubscribe = onValue(usersRef, (snapshot) => { + const data = snapshot.val(); + if (data) { + const athletesArray = Object.keys(data).map(key => { + const u = data[key] || {}; + const p = u.profile || {}; + return { + id: String(key), + name: String(p.name || u.name || 'Unknown'), + category: String(p.category || u.category || 'N/A'), + rfid_tag: String(p.rfid_tag || u.rfid_tag || key), + age: Number(p.age || u.age || 0), + height: Number(p.height || u.height || 0), + weight: Number(p.weight || u.weight || 0) + }; + }); + setAthletes(athletesArray); + } else { + setAthletes([]); + } + }); + + return () => unsubscribe(); + }, []); + + const deleteAthlete = async (id) => { + if (!id) return; + try { + // 1. Hapus dari Firebase (Data Profil) + await remove(ref(rtdb, `users/${id}`)); + + // 2. Hapus dari Firebase (Data Riwayat) - Sangat Penting! + // Kita hapus di kedua path yang mungkin digunakan + await remove(ref(rtdb, `test_history/${id}`)); + await remove(ref(rtdb, `attempts/${id}`)); + + // 3. Sync dengan Backend (SQLite) + // Ini untuk membersihkan data di Leaderboard lokal + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + await fetch(`${API_URL}/api/athletes/${id}`, { + method: 'DELETE' + }); + } catch (backendErr) { + console.warn("Backend sync failed, but Firebase data was removed.", backendErr); + } + + console.log(`Athlete ${id} and all associated data deleted successfully.`); + } catch (err) { + console.error("Failed to delete athlete and data", err); + } + }; + + const getCategoryStyles = (category) => { + const cat = String(category || '').toLowerCase(); + if (cat.includes('dini')) return "bg-blue-100 text-blue-700 border-blue-200"; + if (cat.includes('remaja')) return "bg-emerald-100 text-emerald-700 border-emerald-200"; + if (cat.includes('dewasa')) return "bg-purple-100 text-purple-700 border-purple-200"; + return "bg-slate-100 text-slate-700"; + }; + + const avgAge = athletes.length > 0 ? (athletes.reduce((acc, a) => acc + (Number(a.age) || 0), 0) / athletes.length).toFixed(1) : "0"; + + return ( +
+ {/* Header Section */} +
+
+

+ Dashboard PRO +

+

+ Monitoring Impact & Manajemen Atlet Real-time +

+
+
+ + + +
+
+ + {/* Quick Stats */} +
+ + + + +
+ + + + {/* Athlete List Section */} +
+
+
+

Katalog Atlet

+ + {athletes.length} REKOD + +
+ +
+ Filter: + +
+
+ +
+ {athletes + .filter(a => categoryFilter === 'all' || a.category === categoryFilter) + .sort((a, b) => a.name.localeCompare(b.name)) + .map((athlete) => ( + + +
+
+
+
+ {String(athlete.name || "?").charAt(0).toUpperCase()} +
+
+
+ + ID: {String(athlete.id || "N/A").slice(-6)} + +
+
+
+ + {athlete.name} + +
+ {athlete.category} +
+
+ + + +
+
+

Umur

+

{athlete.age} TH

+
+
+

Tinggi

+

{athlete.height} CM

+
+
+

Berat

+

{athlete.weight} KG

+
+
+ +
+ + + + + + + + + + +
+ +
+ Hapus Atlet + + Anda akan menghapus data {athlete.name} secara permanen. Tindakan ini tidak dapat dibatalkan. + +
+ + + + + + + + +
+
+
+
+ + ))} + + {athletes.length === 0 && ( +
+
+ +
+

Basis Data Kosong

+

+ Daftarkan atlet pertama Anda untuk mulai memantau performa. +

+ + + +
+ )} +
+
+ + setIsHistoryOpen(false)} + /> +
+ ); +}; + +export default Dashboard; diff --git a/frontend/src/pages/Leaderboard.jsx b/frontend/src/pages/Leaderboard.jsx new file mode 100644 index 0000000..6e98118 --- /dev/null +++ b/frontend/src/pages/Leaderboard.jsx @@ -0,0 +1,630 @@ +import React, { useState, useEffect } from 'react'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Trophy, Medal, Download, Calendar, AlertCircle, Filter, FileText, Users } from 'lucide-react'; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Badge } from "@/components/ui/badge"; +import { Separator } from "@/components/ui/separator"; +import { jsPDF } from 'jspdf'; +import autoTable from 'jspdf-autotable'; +import { cn } from "@/lib/utils"; +import { rtdb } from '../firebase'; +import { ref, onValue } from 'firebase/database'; + +const HARI_LIST = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"]; +const BULAN_LIST = ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"]; +const TANGGAL_LIST = Array.from({ length: 31 }, (_, i) => String(i + 1)); +const CATEGORIES = ["Usia dini A", "Usia dini B", "Pra remaja", "Remaja", "Dewasa"]; + +const Leaderboard = () => { + const [leaderboard, setLeaderboard] = useState([]); + const [filteredLeaderboard, setFilteredLeaderboard] = useState([]); + + // New Date Range State + const [startDate, setStartDate] = useState(''); + const [endDate, setEndDate] = useState(''); + const [categoryFilter, setCategoryFilter] = useState('all'); + const [strikeTypeFilter, setStrikeTypeFilter] = useState('all'); + const [currentTime, setCurrentTime] = useState(new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' })); + + const isExportReady = true; + + useEffect(() => { + const usersRef = ref(rtdb, 'users'); + const historyRef = ref(rtdb, 'test_history'); + + // Listen to both nodes to ensure real-time ranking update + const unsubUsers = onValue(usersRef, (snapshot) => { + const userData = snapshot.val() || {}; + + onValue(historyRef, (historySnapshot) => { + const historyData = historySnapshot.val() || {}; + + const athletesArray = Object.keys(userData).map(key => { + const profile = userData[key].profile || {}; + const athleteHistory = historyData[key] || {}; + + let bestPunch = 0; + let bestKick = 0; + + const processAttempt = (data, parentKey) => { + const peak = Number(data?.peak_newton || 0); + let ts = data?.timestamp || 0; + const type = (data?.type || 'pukulan').toLowerCase(); + + // Perbaikan: Ambil timestamp dari nama session jika TS hardware rusak + if (ts < 1000000000000 && parentKey && parentKey.startsWith('session_')) { + const parsedTs = parseInt(parentKey.replace('session_', '')); + if (!isNaN(parsedTs) && parsedTs > 1000000000000) { + ts = parsedTs; + } + } + + if (ts < 1000000000000) { + ts = new Date('2026-04-21T12:00:00').getTime(); + } + + const testDate = new Date(ts); + let includeDate = true; + + if (startDate && endDate) { + const start = new Date(startDate); + start.setHours(0, 0, 0, 0); + const end = new Date(endDate); + end.setHours(23, 59, 59, 999); + includeDate = testDate >= start && testDate <= end; + } + + if (includeDate) { + if (type === 'pukulan' && peak > bestPunch) bestPunch = peak; + if (type === 'tendangan' && peak > bestKick) bestKick = peak; + } + }; + + const traverse = (obj, parentKey = '') => { + if (!obj || typeof obj !== 'object') return; + Object.keys(obj).forEach(k => { + if (k.startsWith('attempt_')) { + processAttempt(obj[k], parentKey); + } else if (typeof obj[k] === 'object') { + traverse(obj[k], k); + } + }); + }; + + traverse(athleteHistory); + + // Logic for display score based on filter + let displayScore = 0; + if (strikeTypeFilter === 'pukulan') displayScore = bestPunch; + else if (strikeTypeFilter === 'tendangan') displayScore = bestKick; + else displayScore = Math.max(bestPunch, bestKick); + + return { + id: key, + name: profile.name || 'Unknown', + category: profile.category || 'N/A', + best_punch: bestPunch, + best_kick: bestKick, + best_score: displayScore + }; + }); + + setLeaderboard(athletesArray); + }, { onlyOnce: false }); + }); + + const timeInterval = setInterval(() => { + setCurrentTime(new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' })); + }, 30000); + + return () => { + unsubUsers(); + clearInterval(timeInterval); + }; + }, [startDate, endDate, strikeTypeFilter]); // Trigger re-fetching when dates or strike type change + + // Apply category filter and sorting + useEffect(() => { + let filtered = [...leaderboard]; + + if (categoryFilter !== 'all') { + filtered = filtered.filter(a => a.category === categoryFilter); + } + + // Only show those with scores > 0 + filtered = filtered.filter(a => a.best_score > 0); + + // Sort descending + filtered.sort((a, b) => b.best_score - a.best_score); + + setFilteredLeaderboard(filtered); + }, [leaderboard, categoryFilter]); + + const getRankIcon = (index) => { + if (index === 0) return
; + if (index === 1) return
; + if (index === 2) return
; + return
#{index + 1}
; + }; + + const exportToPDF = () => { + const generatePDF = (ikspiLogo) => { + try { + const doc = new jsPDF(); + const pageWidth = doc.internal.pageSize.width; + + // --- BACKGROUND PUTIH --- + doc.setFillColor(255, 255, 255); + doc.rect(0, 0, pageWidth, doc.internal.pageSize.height, 'F'); + + // --- TOP KIRI: LOGO IKSPI + IMPACT --- + let impactStartX = 14; + + // Tambahkan Logo IKSPI Paling Kiri (jika ada) + if (ikspiLogo) { + doc.addImage(ikspiLogo, 'PNG', 14, 5, 14, 14); + impactStartX = 32; // Geser teks Impact ke kanan logo + } + + // Simulasi Logo "i" warna biru + doc.setTextColor(37, 99, 235); // blue-600 + doc.setFontSize(22); + doc.setFont("helvetica", "bold"); + doc.text("i", impactStartX, 15); + + doc.setFontSize(9); + doc.setTextColor(15, 23, 42); // slate-900 + doc.text("IMPACT", impactStartX + 6, 13); + doc.setFontSize(6); + doc.setTextColor(100, 116, 139); + doc.text("MONITOR PRO", impactStartX + 6, 17); + + // --- TOP KANAN: INFO CETAK --- + doc.setFontSize(8); + doc.setTextColor(100, 116, 139); + doc.setFont("helvetica", "normal"); + const realTimeJam = new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); + doc.text(`Dicetak pada: ${new Date().toLocaleDateString('id-ID')} ${realTimeJam}`, pageWidth - 14, 12, { align: "right" }); + doc.text(`Sistem: Impact Monitor Pro`, pageWidth - 14, 16, { align: "right" }); + + // --- JUDUL UTAMA --- + doc.setTextColor(15, 23, 42); // navy gelap + doc.setFontSize(26); + doc.setFont("helvetica", "bold"); + doc.text("HALL OF FAME", 14, 33); + + doc.setFontSize(10); + doc.setFont("helvetica", "normal"); + doc.setTextColor(100, 116, 139); + doc.text("Laporan Perankingan Atlet Impact Monitor Pro", 14, 40); + + // --- PERIODE DATA --- + const formattedRange = (startDate && endDate) ? `${startDate} s/d ${endDate}` : "Keseluruhan Waktu"; + doc.setFontSize(9); + doc.setTextColor(71, 85, 105); + doc.text(`Periode Data: ${formattedRange}`, 14, 48); + + // --- 📊 4 KOTAK SUMMARY --- + const totalAtlet = filteredLeaderboard.length; + let maxPower = 0; + let sumPower = 0; + const categoriesSet = new Set(); + + filteredLeaderboard.forEach(a => { + const p = a.best_score || 0; + if (p > maxPower) maxPower = p; + sumPower += p; + if (a.category && a.category !== 'N/A') categoriesSet.add(a.category); + }); + const avgPower = totalAtlet > 0 ? (sumPower / totalAtlet).toFixed(2) : 0; + const totalCategories = categoriesSet.size; + + const cardWidth = (pageWidth - 28 - (3 * 4)) / 4; // 4 kotak dengan margin + const summaryData = [ + { title: "TOTAL ATLET", value: totalAtlet, sub: "Atlet" }, + { title: "RATA-RATA POWER", value: avgPower, sub: "Newton (N)" }, + { title: "POWER TERTINGGI", value: maxPower > 0 ? maxPower.toFixed(2) : 0, sub: "Newton (N)" }, + { title: "KATEGORI", value: totalCategories, sub: "Kategori" } + ]; + + for (let i = 0; i < 4; i++) { + const x = 14 + (i * (cardWidth + 4)); + const y = 55; + doc.setDrawColor(226, 232, 240); // slate-200 border + doc.setFillColor(255, 255, 255); // putih + doc.roundedRect(x, y, cardWidth, 22, 2, 2, 'FD'); + + doc.setFontSize(6); + doc.setTextColor(148, 163, 184); // slate-400 + doc.text(summaryData[i].title, x + cardWidth/2, y + 7, { align: "center" }); + + doc.setFontSize(14); + doc.setTextColor(15, 23, 42); // slate-900 + doc.setFont("helvetica", "bold"); + doc.text(`${summaryData[i].value}`, x + cardWidth/2, y + 14, { align: "center" }); + + doc.setFontSize(6); + doc.setTextColor(148, 163, 184); + doc.setFont("helvetica", "normal"); + doc.text(summaryData[i].sub, x + cardWidth/2, y + 19, { align: "center" }); + } + + // --- 🏆 TOP 3 JUDUL --- + doc.setTextColor(250, 204, 21); // kuning emas + + // Menggambar 3 titik/lingkaran emas sebagai pengganti bintang yang error + doc.setFillColor(250, 204, 21); + doc.circle(pageWidth/2 - 6, 86, 0.8, 'F'); + doc.circle(pageWidth/2, 86, 1.2, 'F'); + doc.circle(pageWidth/2 + 6, 86, 0.8, 'F'); + + doc.setTextColor(15, 23, 42); + doc.setFontSize(11); + doc.text("TOP 3 ATLET", pageWidth/2, 93, { align: "center" }); + + doc.setDrawColor(250, 204, 21); + doc.line(pageWidth/2 - 25, 91, pageWidth/2 - 15, 91); + doc.line(pageWidth/2 + 15, 91, pageWidth/2 + 25, 91); + + // --- 🏆 TOP 3 PODIUM CARDS --- + const top3Width = 50; + const rank1X = (pageWidth / 2) - (top3Width / 2); + const rank2X = rank1X - top3Width - 8; + const rank3X = rank1X + top3Width + 8; + + const drawTopCard = (x, y, width, height, rank, athlete, colorHex) => { + if (!athlete) return; + + // Hex to RGB untuk drawColor + const r = parseInt(colorHex.substring(1,3), 16); + const g = parseInt(colorHex.substring(3,5), 16); + const b = parseInt(colorHex.substring(5,7), 16); + + // Background Kartu + doc.setFillColor(255, 255, 255); + doc.setDrawColor(r, g, b); // Border sesuai medali + doc.roundedRect(x, y, width, height, 3, 3, 'FD'); + + // Lingkaran Medali + doc.setFillColor(r, g, b); + doc.circle(x + width/2, y + 12, 6, 'F'); + doc.setTextColor(255, 255, 255); + doc.setFontSize(10); + doc.setFont("helvetica", "bold"); + doc.text(`${rank}`, x + width/2, y + 15.5, { align: "center" }); + + // Nama Atlet + doc.setTextColor(15, 23, 42); + doc.setFontSize(10); + const name = athlete.name.length > 12 ? athlete.name.substring(0, 10) + '...' : athlete.name; + doc.text(name.toUpperCase(), x + width/2, y + 26, { align: "center" }); + + // Kategori + doc.setTextColor(100, 116, 139); + doc.setFontSize(7); + doc.setFont("helvetica", "normal"); + doc.text(athlete.category, x + width/2, y + 31, { align: "center" }); + + // Power Score + doc.setTextColor(37, 99, 235); // Biru + doc.setFontSize(12); + doc.setFont("helvetica", "bold"); + doc.text(`${athlete.best_score ? athlete.best_score.toFixed(2) : 0} N`, x + width/2, y + 37, { align: "center" }); + }; + + // Rank 2 (Kiri) + drawTopCard(rank2X, 103, top3Width, 42, 2, filteredLeaderboard[1], "#94A3B8"); // Silver + // Rank 1 (Tengah - Lebih Tinggi & Lebar) + drawTopCard(rank1X, 98, top3Width + 4, 47, 1, filteredLeaderboard[0], "#FBBF24"); // Emas + // Rank 3 (Kanan) + drawTopCard(rank3X, 103, top3Width, 42, 3, filteredLeaderboard[2], "#D97706"); // Perunggu + + // --- 📋 TABEL PERINGKAT LENGKAP --- + doc.setFontSize(12); + doc.setFont("helvetica", "bold"); + doc.setTextColor(15, 23, 42); + doc.text("PERINGKAT LENGKAP", 14, 158); + + // Dinamis Kolom berdasarkan Filter + let tableColumn = ["RANK", "NAMA ATLET", "KATEGORI"]; + if (strikeTypeFilter === 'all') { + tableColumn.push("PUKULAN (N)", "TENDANGAN (N)", "BEST SCORE (N)"); + } else if (strikeTypeFilter === 'pukulan') { + tableColumn.push("PUKULAN (N)"); + } else { + tableColumn.push("TENDANGAN (N)"); + } + + const tableRows = filteredLeaderboard.map((athlete, index) => { + const row = [ + `#${index + 1}`, + athlete.name.toUpperCase(), + athlete.category + ]; + + if (strikeTypeFilter === 'all') { + row.push( + athlete.best_punch ? athlete.best_punch.toFixed(1) : '-', + athlete.best_kick ? athlete.best_kick.toFixed(1) : '-', + athlete.best_score ? athlete.best_score.toFixed(2) : '0.00' + ); + } else if (strikeTypeFilter === 'pukulan') { + row.push(athlete.best_punch ? athlete.best_punch.toFixed(2) : '0.00'); + } else { + row.push(athlete.best_kick ? athlete.best_kick.toFixed(2) : '0.00'); + } + return row; + }); + + // Style Kolom Dinamis + const colStyles = { + 0: { halign: 'center', fontStyle: 'bold', textColor: [37, 99, 235] }, + 1: { halign: 'left', fontStyle: 'bold', textColor: [15, 23, 42] }, + 2: { halign: 'center', textColor: [100, 116, 139] } + }; + + if (strikeTypeFilter === 'all') { + colStyles[3] = { halign: 'center', textColor: [15, 23, 42] }; + colStyles[4] = { halign: 'center', textColor: [15, 23, 42] }; + colStyles[5] = { halign: 'center', fontStyle: 'bold', textColor: [37, 99, 235] }; + } else { + colStyles[3] = { halign: 'center', fontStyle: 'bold', textColor: [15, 23, 42] }; + } + + autoTable(doc, { + head: [tableColumn], + body: tableRows, + startY: 163, + theme: 'grid', + headStyles: { + fillColor: [15, 23, 42], + textColor: [255, 255, 255], + fontStyle: 'bold', + halign: 'center', + fontSize: 8, + cellPadding: 4 + }, + columnStyles: colStyles, + alternateRowStyles: { fillColor: [248, 250, 252] }, + styles: { fontSize: 7, cellPadding: 4, lineColor: [226, 232, 240], lineWidth: 0.1 }, + + // --- FOOTER BAWAH --- + didDrawPage: function (data) { + let pageCount = doc.internal.getNumberOfPages(); + doc.setFontSize(7); + doc.setTextColor(148, 163, 184); // slate-400 + doc.text("Laporan ini digenerate secara otomatis oleh Impact Monitor Pro", 14, doc.internal.pageSize.height - 12); + doc.text("Sistem pemantauan dan analisis performa atlet berbasis teknologi.", 14, doc.internal.pageSize.height - 8); + + doc.text(`Halaman ${pageCount} dari {total_pages}`, doc.internal.pageSize.width - 14, doc.internal.pageSize.height - 10, { align: 'right' }); + } + }); + + // Kalkulasi Total Halaman untuk Footer + if (typeof doc.putTotalPages === 'function') { + doc.putTotalPages("{total_pages}"); + } + + doc.save(`Leaderboard_Silat_${startDate || 'All'}_to_${endDate || 'Time'}.pdf`); + } catch (error) { + console.error("Error PDF Generate:", error); + } + }; + + // --- PROSES MUAT LOGO --- + // Jika ada logo.png di dalam folder public, akan otomatis masuk ke pojok atas + const img = new Image(); + img.src = '/logo.png'; + img.onload = () => generatePDF(img); + img.onerror = () => generatePDF(null); // Terus lanjut tanpa logo jika gagal dimuat + }; + + return ( +
+ {/* Page Header */} +
+
+
+
+ +
+

Hall of Fame

+
+

+ Top Performers +

+
+ + {/* Horizontal Filter Bar */} +
+
+ + +
+ +
+ + +
+ +
+ + setStartDate(e.target.value)} + className="h-11 px-4 rounded-xl bg-white border-none shadow-sm font-bold text-sm outline-none focus:ring-2 focus:ring-primary/20" + /> +
+ +
+ + setEndDate(e.target.value)} + className="h-11 px-4 rounded-xl bg-white border-none shadow-sm font-bold text-sm outline-none focus:ring-2 focus:ring-primary/20" + /> +
+ +
+ + + +
+
+
+ +
+ {/* Leaderboard Table */} + +
+
+
+ +
+
+

Katalog Peringkat

+

{filteredLeaderboard.length} Rekod Atlet

+
+
+
+
+ + {(startDate && endDate) ? `${startDate} — ${endDate}` : "Semua Waktu"} + +

Update Terakhir

+
+

{currentTime} WIB

+
+
+ +
+ + + + Peringkat + Data Atlet + Kategori + + {(strikeTypeFilter === 'all' || strikeTypeFilter === 'pukulan') && ( + Pukulan (N) + )} + + {(strikeTypeFilter === 'all' || strikeTypeFilter === 'tendangan') && ( + Tendangan (N) + )} + + Power Score + + + + {filteredLeaderboard.map((athlete, index) => ( + + {getRankIcon(index)} + +
+ {athlete.name} + Athlete ID: {athlete.id || 'N/A'} +
+
+ + + {athlete.category} + + + + {(strikeTypeFilter === 'all' || strikeTypeFilter === 'pukulan') && ( + + = athlete.best_kick && athlete.best_punch > 0)) ? "text-primary" : "text-slate-400" + )}> + {athlete.best_punch ? athlete.best_punch.toFixed(1) : '-'} + + + )} + + {(strikeTypeFilter === 'all' || strikeTypeFilter === 'tendangan') && ( + + athlete.best_punch)) ? "text-primary" : "text-slate-400" + )}> + {athlete.best_kick ? athlete.best_kick.toFixed(1) : '-'} + + + )} + + +
+ + {athlete.best_score ? athlete.best_score.toFixed(2) : '0.00'} + + + {strikeTypeFilter === 'pukulan' ? 'Pukulan' : (strikeTypeFilter === 'tendangan' ? 'Tendangan' : (athlete.best_punch >= athlete.best_kick ? 'Pukulan' : 'Tendangan'))} + +
+
+
+ ))} + {filteredLeaderboard.length === 0 && ( + + +
+ + Belum Ada Data Tersedia untuk filter ini +
+
+
+ )} +
+
+
+
+
+
+ ); +}; + + +export default Leaderboard; diff --git a/frontend/src/pages/LiveTest.jsx b/frontend/src/pages/LiveTest.jsx new file mode 100644 index 0000000..08a183e --- /dev/null +++ b/frontend/src/pages/LiveTest.jsx @@ -0,0 +1,439 @@ +import React, { useEffect, useState, useRef } from 'react'; +import { useParams } from 'react-router-dom'; +import { rtdb } from '../firebase'; +import { ref, onValue, get, set, off, remove } from 'firebase/database'; +import { Play, Square, Activity, Target, Zap, Waves, ChevronUp, RotateCcw } from 'lucide-react'; +import { cn } from "@/lib/utils"; +import { + AreaChart, + Area, + XAxis, + YAxis, + CartesianGrid, + ResponsiveContainer, + ReferenceLine +} from 'recharts'; + +const GRAPH_BARS = 150; + +const LiveTest = () => { + const { id } = useParams(); + const [athlete, setAthlete] = useState(null); + const [currentForce, setCurrentForce] = useState(0); + const [sessionPeak, setSessionPeak] = useState(0); + const [attempts, setAttempts] = useState([]); + const [isTesting, setIsTesting] = useState(false); + const [bestScore, setBestScore] = useState(0); + const [forceHistory, setForceHistory] = useState(Array(GRAPH_BARS).fill({ value: 0 }).map((_, i) => ({ time: i, value: 0 }))); + const [strikeType, setStrikeType] = useState('pukulan'); + + // 1. Fetch Athlete Details + useEffect(() => { + const fetchAthlete = async () => { + try { + const athleteRef = ref(rtdb, `users/${id}`); + const snapshot = await get(athleteRef); + if (snapshot.exists()) { + const data = snapshot.val(); + setAthlete(data.profile ? { ...data.profile, id } : { id, ...data }); + } + } catch (err) { + console.error("Error fetching athlete:", err); + } + }; + fetchAthlete(); + }, [id]); + + // 2. Listen to Live Data and History + useEffect(() => { + if (!id) return; + + const statusRef = ref(rtdb, 'system/test_status'); + const liveRef = ref(rtdb, 'realtime/current_force'); + const historyRef = ref(rtdb, `test_history/${id}`); + + onValue(statusRef, (snapshot) => { + const status = snapshot.val(); + const testing = status === 'measuring'; + setIsTesting(testing); + if (testing) { + setSessionPeak(0); + setCurrentForce(0); + } + }); + + onValue(liveRef, (snapshot) => { + const force = Number(snapshot.val() || 0); + setCurrentForce(force); + if (force > sessionPeak) { + setSessionPeak(force); + } + // Rolling graph history (Muncul dari kanan ke kiri - sinkron dengan Monitor) + setForceHistory(prev => { + const newData = { time: 0, value: force }; + // Masukkan data baru di awal [newData], buang yang terakhir di belakang + const updated = [newData, ...prev.slice(0, -1)]; + // Maintain indices for re-rendering + return updated.map((d, idx) => ({ ...d, time: idx })); + }); + }); + + onValue(historyRef, (snapshot) => { + const data = snapshot.val(); + if (data) { + const attemptArray = []; + let max = 0; + Object.keys(data).forEach(key => { + if (key.startsWith('attempt_')) { + const score = data[key].peak_newton || 0; + attemptArray.push({ + attemptNumber: key.split('_')[1], + force: score + }); + if (score > max) max = score; + } + }); + setAttempts(attemptArray.sort((a, b) => a.attemptNumber - b.attemptNumber)); + setBestScore(max); + } + }); + + return () => { + off(statusRef); + off(liveRef); + off(historyRef); + }; + }, [id, sessionPeak]); + + const handleStart = async () => { + if (!id) return; + try { + const nextAttempt = attempts.length + 1; + // Format command: ID|Attempt|StrikeType + await set(ref(rtdb, 'test_command'), `${id}|${nextAttempt}|${strikeType}`); + } catch (err) { + console.error("Failed to start test:", err); + } + }; + + const resetAttempts = async () => { + if (!id || isTesting) return; + try { + await remove(ref(rtdb, `test_history/${id}`)); + setAttempts([]); + setBestScore(0); + } catch (err) { + console.error("Failed to reset attempts:", err); + } + }; + + const handleStop = async () => { + try { + await set(ref(rtdb, 'system/test_status'), 'idle'); + await set(ref(rtdb, 'test_command'), ''); + } catch (err) { + console.error("Failed to stop test:", err); + } + }; + + if (!athlete) return
Memuat Data Atlet...
; + + const forcePercentage = Math.min(100, (currentForce / 1000) * 100); + const peakPercentage = Math.min(100, (sessionPeak / 1000) * 100); + + // Font size based on digit count (Sinkron dengan Monitor) + const gaugeFontSize = currentForce >= 10000 + ? 'text-[5rem] md:text-[7rem]' + : currentForce >= 1000 + ? 'text-[7rem] md:text-[10rem]' + : currentForce >= 100 + ? 'text-[9rem] md:text-[13rem]' + : 'text-[11rem] md:text-[16rem]'; + + return ( +
+ {/* Header Section */} +
+
+ +
+ +
+
+
+ {athlete.name?.charAt(0)} +
+ {isTesting && ( +
+ )} +
+
+

{athlete.name}

+
+ {athlete.category || 'Atlete'} + {athlete.weight || '-'} KG +
+
+
+ +
+
+ Impact Tertinggi + + {bestScore.toFixed(0)} N + +
+
+ Status Sistem + + {isTesting ? "MEASURING" : "READY"} + +
+
+
+ +
+ {/* Main Gauge Display */} +
+
+ + {/* Background Deco */} +
+ FORCE +
+ + {/* Power Meter Vertical */} +
+ {/* Scale Indicators */} +
+ 1000 + 750 + 500 + 250 + 0 +
+ + {/* The Main Power Bar */} +
800 ? "bg-gradient-to-t from-orange-500 to-red-600" : + currentForce > 400 ? "bg-gradient-to-t from-emerald-400 to-yellow-500" : + "bg-gradient-to-t from-blue-500 to-emerald-400" + )} + style={{ height: `${forcePercentage}%` }} + > + {/* Impact Glow */} +
+
+ + {/* Ghost Peak Marker */} +
+
+ PEAK: {sessionPeak.toFixed(0)}N +
+
+
+ + {/* Textual Feedback */} +
+
+
+ +

Live Impact Monitoring

+
+

+ Sensor mendeteksi osilasi gaya pada 100Hz. Pukul target untuk melihat lonjakan energi real-time. +

+ +
+ {/* Strike Type Toggle */} +
+ +
+ + +
+
+ +
+ Live Pressure +
+ {currentForce.toFixed(0)} +
+ Newton +
+ + {sessionPeak > 0 && ( +
+ Puncak Sesi Ini +
+ {sessionPeak.toFixed(0)} Newton +
+
+ )} +
+
+ +
+ + +
+
+
+ + {/* Real-time Oscilloscope Waveform */} +
+
+
+
+ +
+

Force Waveform

+
+ Live Trace (5.0s) +
+ +
+ + + + + + + + + + + Math.max(dataMax, 1000)]} + /> + + {sessionPeak > 0 && ( + + )} + + +
+
+
+ + {/* Sidebar Stats */} +
+ {/* History List */} +
+
+

Log Hasil

+
+ {attempts.length > 0 && !isTesting && ( + + )} + +
+
+ +
+ {attempts.length === 0 ? ( +
+

Kosong

+
+ ) : ( + attempts.map((attempt, idx) => ( +
+
+ Lari #{attempt.attemptNumber} +
+ {attempt.force} N +
+
+
+ +
+
+ )) + )} +
+
+ +
+
+ Skor Legenda +
1000N
+
+ +
+
+
+
+ ); +}; + +export default LiveTest; diff --git a/frontend/src/pages/Monitor.jsx b/frontend/src/pages/Monitor.jsx new file mode 100644 index 0000000..ce651ab --- /dev/null +++ b/frontend/src/pages/Monitor.jsx @@ -0,0 +1,578 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { rtdb } from '../firebase'; +import { ref, onValue, set, off } from 'firebase/database'; +import { Badge } from "@/components/ui/badge"; +import { + Activity, + Play, + Square, + Target, + Waves, + Zap, + MessageSquare, + TrendingUp, + RotateCcw +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + AreaChart, + Area, + XAxis, + YAxis, + CartesianGrid, + ResponsiveContainer, + ReferenceLine +} from 'recharts'; + +const GRAPH_BARS = 50; // Jarak diperlebar (dari sebelumnya 150 titik menjadi 50 titik) + +const Monitor = () => { + const [athletes, setAthletes] = useState([]); + const [selectedAthlete, setSelectedAthlete] = useState(''); + const [isTesting, setIsTesting] = useState(false); + const [livePeak, setLivePeak] = useState(0); + const [liveForce, setLiveForce] = useState(0); + const [attempts, setAttempts] = useState([]); + const [forceHistory, setForceHistory] = useState(Array(GRAPH_BARS).fill({ value: 0 }).map((_, i) => ({ time: i, value: 0 }))); + const [currentAttemptIndex, setCurrentAttemptIndex] = useState(0); + const [animatedValue, setAnimatedValue] = useState(0); + const [currentSessionId, setCurrentSessionId] = useState(null); + const [strikeType, setStrikeType] = useState('pukulan'); + + // Track live peak locally for immediate responsiveness + const localPeakRef = useRef(0); + const isTestingRef = useRef(false); // Ref untuk sinkronisasi dengan listener Firebase + + // 1. Fetch Athletes + useEffect(() => { + const r = ref(rtdb, 'users'); + const unsub = onValue(r, (snap) => { + const data = snap.val(); + if (data) { + const arr = Object.keys(data).map(key => ({ + id: String(key), + name: String(data[key]?.profile?.name || data[key]?.name || 'Unknown'), + })); + setAthletes(arr); + } + }); + return () => off(r, 'value', unsub); + }, []); + + // 2. Load History (Current Session) + useEffect(() => { + // Reset seketika saat atlet berubah agar tidak ada sisa data atlet sebelumnya + setLiveForce(0); + setLivePeak(0); + setAnimatedValue(0); + setForceHistory(Array(GRAPH_BARS).fill({ value: 0 }).map((_, i) => ({ time: i, value: 0 }))); + + if (!selectedAthlete) { + setAttempts([]); + setCurrentSessionId(null); + return; + } + + const r = ref(rtdb, `test_history/${selectedAthlete}`); + const unsub = onValue(r, (snap) => { + const data = snap.val(); + if (data && typeof data === 'object') { + // Find all sessions or legacy attempts + const sessionKeys = Object.keys(data).filter(k => k.startsWith('session_')).sort().reverse(); + + // If there are sessions, use the latest one by default (unless we just started a new one) + // If no sessions but there are legacy attempt_ keys, treat them as a "Legacy" session + let targetSessionData = null; + let activeSessionId = currentSessionId; + + if (!activeSessionId) { + if (sessionKeys.length > 0) { + activeSessionId = sessionKeys[0]; + } else if (Object.keys(data).some(k => k.startsWith('attempt_'))) { + activeSessionId = 'legacy'; + } + } + + if (activeSessionId === 'legacy') { + targetSessionData = data; + } else if (activeSessionId) { + targetSessionData = data[activeSessionId]; + } + + setCurrentSessionId(activeSessionId); + + if (targetSessionData) { + const arr = []; + Object.keys(targetSessionData).forEach(k => { + if (k.startsWith('attempt_')) { + const attemptNum = parseInt(k.replace('attempt_', '')); + arr.push({ + number: attemptNum, + peak: Number(targetSessionData[k]?.peak_newton || 0) + }); + } + }); + arr.sort((a, b) => a.number - b.number); + setAttempts(arr); + } else { + setAttempts([]); + } + } else { + setAttempts([]); + setCurrentSessionId(null); + } + }); + return () => off(r, 'value', unsub); + }, [selectedAthlete, currentSessionId]); + + // 3. Real-time Listeners + useEffect(() => { + const sRef = ref(rtdb, 'system/test_status'); + const lRef = ref(rtdb, 'realtime/current_force'); + const pRef = ref(rtdb, 'realtime/peak_force'); + + const unsubS = onValue(sRef, (s) => { + const status = s.val(); + const testing = status === 'measuring' || status === 'waiting'; + setIsTesting(testing); + isTestingRef.current = testing; // Update ref juga + if (!testing) { + // Test selesai, reset local peak + localPeakRef.current = 0; + } + }); + + const unsubL = onValue(lRef, (s) => { + const val = Number(s.val() || 0); + setLiveForce(val); + // Update local peak tracking + if (val > localPeakRef.current) { + localPeakRef.current = val; + } + // Rolling graph history (Muncul dari kiri ke kanan) + setForceHistory(prev => { + const newData = { time: 0, value: val }; + // Masukkan data baru di awal [newData], buang yang terakhir di belakang + const updated = [newData, ...prev.slice(0, -1)]; + // Maintain indices for re-rendering + return updated.map((d, idx) => ({ ...d, time: idx })); + }); + }); + + const unsubP = onValue(pRef, (s) => setLivePeak(Number(s.val() || 0))); + + return () => { + off(sRef, 'value', unsubS); + off(lRef, 'value', unsubL); + off(pRef, 'value', unsubP); + }; + }, []); + + // 4. Count-up Animation Logic + useEffect(() => { + if (!isTesting) { + // Jangan reset ke 0 agar angka tetap stay di layar setelah selesai + return; + } + + let animationFrame; + const animate = () => { + setAnimatedValue(prev => { + if (prev < livePeak) { + // Cepat bertambah jika selisih besar, melambat jika dekat + const diff = livePeak - prev; + const step = Math.max(1, Math.ceil(diff / 5)); // "urut" atau sequential cepat + return Math.min(livePeak, prev + step); + } + return prev; + }); + animationFrame = requestAnimationFrame(animate); + }; + + animationFrame = requestAnimationFrame(animate); + return () => cancelAnimationFrame(animationFrame); + }, [livePeak, isTesting]); + + const startTest = async () => { + if (!selectedAthlete) return; + + // Cek apakah sesi saat ini sudah penuh (3 percobaan selesai) + const isSessionFull = attempts.length >= 3 && attempts.every(a => a.peak > 0); + let sessionId = currentSessionId; + + // Mulai sesi baru jika sesi lama penuh atau belum ada sesi/Legacy + if (!sessionId || isSessionFull || sessionId === 'legacy') { + sessionId = `session_${new Date().getTime()}`; + setCurrentSessionId(sessionId); + setAttempts([]); // Reset UI lokal seketika + } + + // Temukan slot pertama (1, 2, atau 3) yang masih kosong di sesi ini + const firstEmptySlot = [1, 2, 3].find(num => { + const found = attempts.find(a => a.number === num); + return !found || found.peak <= 0; + }) || 1; + + const nextId = firstEmptySlot; + setCurrentAttemptIndex(nextId - 1); + + console.log(`Starting test for ${selectedAthlete} in session ${sessionId} slot ${nextId}`); + + // Reset semua nilai sebelum sesi baru + localPeakRef.current = 0; + await set(ref(rtdb, 'realtime/current_force'), 0); + await set(ref(rtdb, 'realtime/peak_force'), 0); + setLivePeak(0); + setLiveForce(0); + setAnimatedValue(0); + setForceHistory(Array(GRAPH_BARS).fill({ value: 0 }).map((_, i) => ({ time: i, value: 0 }))); + + // Trik: UID diisi path 'athleteId/sessionId' agar firmware menyimpan ke folder tersebut + await set(ref(rtdb, 'test_command'), `${selectedAthlete}/${sessionId}|${nextId}|${strikeType}`); + }; + + const stopTest = async () => { + await set(ref(rtdb, 'system/test_status'), 'idle'); + await set(ref(rtdb, 'test_command'), ''); + }; + + const resetAttempts = async () => { + if (!selectedAthlete || isTesting) return; + + if (currentSessionId && currentSessionId !== 'legacy') { + // Hanya hapus sesi yang aktif saat ini, jangan hapus seluruh riwayat atlet + await set(ref(rtdb, `test_history/${selectedAthlete}/${currentSessionId}`), null); + } else { + await set(ref(rtdb, `test_history/${selectedAthlete}`), null); + } + + setAttempts([]); + }; + + const currentAthlete = athletes.find(a => a.id === selectedAthlete); + + // Display values + // PERBAIKAN: Jika atlet belum dipilih, paksa angka ke 0. Jika sudah, gunakan logika persistence. + const latestAttemptPeak = attempts.length > 0 ? attempts[attempts.length - 1].peak : 0; + + const displayForce = !selectedAthlete ? 0 : (isTesting ? animatedValue : (liveForce > 0 ? liveForce : latestAttemptPeak)); + const displayPeak = !selectedAthlete ? 0 : (isTesting ? livePeak : (livePeak > 0 ? livePeak : latestAttemptPeak)); + + // Dynamic scale for graph + const maxGraph = Math.max(...forceHistory.map(d => d.value), 100); + + // Font size based on digit count + const gaugeFontSize = displayForce >= 10000 + ? 'text-[7rem]' + : displayForce >= 1000 + ? 'text-[10rem]' + : displayForce >= 100 + ? 'text-[13rem]' + : 'text-[16rem]'; + + return ( +
+ + {/* ─── Sidebar Kiri: SESI LATIHAN ────────────────────────── */} +
+
+
+
+
+
+ +
+
+

Sesi Latihan

+

Konfigurasi audit performa

+
+
+ +
+ {/* Pilih Atlet */} +
+ + +
+ + {/* Pilih Jenis Serangan */} +
+ +
+ + +
+
+ + {/* Tombol Mulai / Hentikan */} + {!isTesting ? ( + + ) : ( + + )} + + {/* Logging Percobaan */} +
+
+

Logging Percobaan

+ {attempts.length > 0 && !isTesting && ( + + )} +
+ {[0, 1, 2].map(i => { + const isActive = isTesting && currentAttemptIndex === i; + const attemptData = attempts[i]; + const hasData = attemptData !== undefined; + + // Nilai yang ditampilkan: + // - Jika sedang aktif (testing): tampilkan animatedValue (count-up) + // - Jika sudah selesai: tampilkan peak dari history + // - Jika belum: tampilkan 0 + const displayVal = isActive + ? animatedValue + : (hasData ? attemptData.peak : 0); + + return ( +
+
+
+ {i + 1} +
+
+ Attempt {i + 1} + + {isActive ? "Recording..." : (hasData ? "Finished" : "Ready")} + +
+
+
+ {displayVal > 0 ? Number(displayVal).toFixed(0) : "0"} N +
+
+ ); + })} +
+
+
+
+
+ + {/* ─── Main: Center + Right ──────────────────────────────── */} +
+
+ + {/* CENTER GAUGE */} +
+ {/* Decorative circles */} +
+
+
+
+ + + {isTesting ? "Sensor Active Tracking" : "Sensor Standby Mode"} + + +

Gaya Saat Ini

+ + {/* ANGKA NEWTON */} +
+ 0 ? "text-slate-700" : "text-slate-100", + gaugeFontSize + )}> + {displayForce.toFixed(0)} + + NEWTON +
+ + {/* Badge Peak */} +
+ + + Peak: {displayPeak.toFixed(0)} N + +
+ +
+
+ Target: {">"}800N +
+
+ Athlete: {currentAthlete?.name || "Pilih Atlet"} +
+
+
+ + {/* RIGHT ANALYSIS CARD */} +
+
+
+
+ +
+

Analisis Dampak

+
+ +
+ {/* Progress bar */} +
+
+ Efisiensi Serangan + + {(Math.min(100, displayPeak / 1000 * 100)).toFixed(1)}% + +
+
+
+
+
+ 0 N + 1000 N +
+
+ +
+
+ +
+ Saran Pelatih +

+ "Fokus pada kecepatan putaran pinggang untuk menambah gaya ledak." +

+
+
+
+
+
+ + {/* BOTTOM — Live Force Stream Graph */} +
+
+
+
+
+ +
+

Live Force Stream

+
+

Osiloskop gaya real-time dari sensor.

+
+
+
+ + {isTesting ? "Live" : "Idle"} + +
+
+ + {/* Real-time Oscilloscope Waveform */} +
+ + + + + + + + + + + + + {isTesting && ( + + )} + + +
+ +
+ Timeline (5s) + {(maxGraph / 2).toFixed(0)} N + Max Scale: {maxGraph.toFixed(0)} N +
+ +
+
+
+
+ ); +}; + +export default Monitor; diff --git a/frontend/src/pages/Register.jsx b/frontend/src/pages/Register.jsx new file mode 100644 index 0000000..3734a57 --- /dev/null +++ b/frontend/src/pages/Register.jsx @@ -0,0 +1,214 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { rtdb } from '../firebase'; +import { ref, onValue, set, get } from 'firebase/database'; +import { Radio, Scan, Save, User as UserIcon, Calendar, Ruler, Weight, Tag, Activity } from 'lucide-react'; +import { Card, CardContent, CardTitle, CardDescription } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Button } from "@/components/ui/button"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Separator } from "@/components/ui/separator"; + +const CATEGORIES = ["Usia dini A", "Usia dini B", "Pra remaja", "Remaja", "Dewasa"]; + +const Register = () => { + const navigate = useNavigate(); + + const [formData, setFormData] = useState({ + name: '', + age: '', + height: '', + weight: '', + category: 'Usia dini A', + rfid_tag: '' + }); + + const [scanning, setScanning] = useState(true); + const [loading, setLoading] = useState(false); + const [rfidError, setRfidError] = useState(''); + + // ================= RFID LISTENER ================= + useEffect(() => { + const scannedRef = ref(rtdb, 'system/last_scanned'); + + const unsubscribe = onValue(scannedRef, async (snapshot) => { + const val = snapshot.val(); + if (val && typeof val === 'string') { + try { + const userRef = ref(rtdb, `users/${val}`); + const userSnap = await get(userRef); + + if (userSnap.exists()) { + setRfidError("UID sudah terdaftar!"); + setFormData(prev => ({ ...prev, rfid_tag: '' })); + setScanning(true); + + await set(scannedRef, ""); // Reset system/last_scanned + + // Clear error message after 3 seconds + setTimeout(() => setRfidError(''), 3000); + } else { + setRfidError(''); + setFormData(prev => ({ ...prev, rfid_tag: val })); + setScanning(false); + } + } catch (error) { + console.error("Error checking UID:", error); + } + } + }); + + return () => unsubscribe(); + }, []); + + // ================= HANDLE INPUT ================= + const handleChange = (e) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + + // ================= SUBMIT ================= + const handleSubmit = async (e) => { + e.preventDefault(); + + if (!formData.rfid_tag) { + alert('Silakan scan kartu RFID terlebih dahulu.'); + return; + } + + setLoading(true); + + try { + const uid = formData.rfid_tag; + + const payload = { + ...formData, + id: uid, + createdAt: new Date().toISOString() + }; + + const userRef = ref(rtdb, `users/${uid}`); + + await set(userRef, { + profile: payload, + total_tests: 0, + best_power: 0 + }); + + // 🔥 RESET RFID (PENTING) + await set(ref(rtdb, "system/last_scanned"), ""); + + alert('✅ Data berhasil disimpan'); + + // reset form + setFormData({ + name: '', + age: '', + height: '', + weight: '', + category: 'Usia dini A', + rfid_tag: '' + }); + + setScanning(true); + + navigate('/'); + + } catch (err) { + alert('❌ Gagal: ' + err.message); + } + + setLoading(false); + }; + + return ( +
+ + + {/* HEADER */} +
+ + PENDAFTARAN ATLET + + + Integrasi RFID & Sistem ImpactMonitor + +
+ +
+ + {/* IDENTITAS */} +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + + + {/* FISIK */} +
+
+ + +
+
+ + +
+
+ + + + {/* RFID */} +
+ +

+ {rfidError ? 'UID SUDAH TERDAFTAR' : (formData.rfid_tag || 'DEKATKAN KARTU')} +

+

+ {rfidError ? 'Gunakan kartu lain' : (scanning ? 'Menunggu scan...' : 'RFID terdeteksi')} +

+
+ + {/* BUTTON */} + + + +
+
+ ); +}; + +export default Register; \ No newline at end of file diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx new file mode 100644 index 0000000..6383519 --- /dev/null +++ b/frontend/src/pages/Settings.jsx @@ -0,0 +1,250 @@ +import React, { useState, useEffect } from 'react'; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Settings as SettingsIcon, ShieldCheck, KeyRound, AlertCircle, Users, UserPlus, Trash2 } from 'lucide-react'; +import { useAuth } from '@/context/AuthContext'; + +const Settings = () => { + const { user } = useAuth(); + const [passwords, setPasswords] = useState({ + oldPassword: '', + newPassword: '', + confirmPassword: '' + }); + + const [newAdmin, setNewAdmin] = useState({ username: '', password: '' }); + const [adminUsers, setAdminUsers] = useState([]); + const [status, setStatus] = useState({ type: '', message: '' }); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + fetchAdminUsers(); + }, []); + + const fetchAdminUsers = async () => { + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const response = await fetch(`${API_URL}/api/admin/users`); + const data = await response.json(); + setAdminUsers(data); + } catch (error) { + console.error('Gagal mengambil daftar admin'); + } + }; + + const handleUpdatePassword = async (e) => { + e.preventDefault(); + if (passwords.newPassword !== passwords.confirmPassword) { + setStatus({ type: 'error', message: 'Konfirmasi password tidak cocok' }); + return; + } + + setIsLoading(true); + setStatus({ type: '', message: '' }); + + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const response = await fetch(`${API_URL}/api/admin/update-password`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + username: user?.username, + oldPassword: passwords.oldPassword, + newPassword: passwords.newPassword + }) + }); + + const data = await response.json(); + if (data.success) { + setStatus({ type: 'success', message: 'Password berhasil diperbarui!' }); + setPasswords({ oldPassword: '', newPassword: '', confirmPassword: '' }); + } else { + setStatus({ type: 'error', message: data.message || 'Gagal memperbarui password' }); + } + } catch (error) { + setStatus({ type: 'error', message: 'Koneksi ke server gagal' }); + } finally { + setIsLoading(false); + } + }; + + const handleAddAdmin = async (e) => { + e.preventDefault(); + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + const response = await fetch(`${API_URL}/api/admin/users`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(newAdmin) + }); + const data = await response.json(); + if (data.success) { + setNewAdmin({ username: '', password: '' }); + fetchAdminUsers(); + } + } catch (error) { + console.error('Gagal menambah admin'); + } + }; + + const handleDeleteAdmin = async (id) => { + if (adminUsers.length <= 1) return alert('Minimal harus ada 1 admin!'); + if (!confirm('Hapus admin ini?')) return; + + try { + const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; + await fetch(`${API_URL}/api/admin/users/${id}`, { method: 'DELETE' }); + fetchAdminUsers(); + } catch (error) { + console.error('Gagal menghapus admin'); + } + }; + + return ( +
+
+

+ + Pengaturan Sistem +

+

Kelola keamanan dan pengguna admin aplikasi Impact Monitor.

+
+ +
+ {/* Bagian Ganti Password */} + + + + + Ganti Password Saya + + Login sebagai: {user?.username} + +
+ +
+ + setPasswords({...passwords, oldPassword: e.target.value})} + required + /> +
+
+ + setPasswords({...passwords, newPassword: e.target.value})} + required + /> +
+
+ + setPasswords({...passwords, confirmPassword: e.target.value})} + required + /> +
+ + {status.message && ( +
+ {status.type === 'error' && } + {status.message} +
+ )} +
+ + + +
+
+ + {/* Manajemen User Admin */} +
+ + + + + Daftar Admin + + + +
+ {adminUsers.map(admin => ( +
+
+
+ {admin.username.charAt(0).toUpperCase()} +
+ {admin.username} +
+ {admin.username !== user?.username && ( + + )} +
+ ))} +
+
+
+ + + + + + Tambah Admin Baru + + +
+ +
+ + setNewAdmin({...newAdmin, username: e.target.value})} + placeholder="Ketik username baru..." + required + /> +
+
+ + setNewAdmin({...newAdmin, password: e.target.value})} + required + /> +
+
+ + + +
+
+
+
+
+ ); +}; + +export default Settings; + diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..f11398b --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,59 @@ +export default { + darkMode: ["class"], + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: { + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + } + } + }, + plugins: [require("tailwindcss-animate")], +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js new file mode 100644 index 0000000..5790e82 --- /dev/null +++ b/frontend/vite.config.js @@ -0,0 +1,12 @@ +import path from "path" +import react from "@vitejs/plugin-react" +import { defineConfig } from "vite" + +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..483e239 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1058 @@ +{ + "name": "Silat", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "firebase": "^12.11.0" + } + }, + "node_modules/@firebase/ai": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.10.0.tgz", + "integrity": "sha512-1lI6HomyoO/8RSJb6ItyHLpHnB2z27m5F4aX/Vpi1nhwWoxdNjkq+6UQOykHyCE0KairojOE5qQ20i1tnF0nNA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.21", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.21.tgz", + "integrity": "sha512-j2y2q65BlgLGB5Pwjhv/Jopw2X/TBTzvAtI5z/DSp56U4wBj7LfhBfzbdCtFPges+Wz0g55GdoawXibOH5jGng==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.27.tgz", + "integrity": "sha512-ZObpYpAxL6JfgH7GnvlDD0sbzGZ0o4nijV8skatV9ZX49hJtCYbFqaEcPYptT94rgX1KUoKEderC7/fa7hybtw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.21", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz", + "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.10.tgz", + "integrity": "sha512-PlPhdtjgWUra+LImQTnXOUqUa/jcufZhizdR93ZjlQSS3ahCtDTG6pJw7j0OwFal18DQjICXfeVNsUUrcNisfA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.2.tgz", + "integrity": "sha512-jcXQVMHAQ5AEKzVD5C7s5fmAYeFOuN6lAJeNTgZK2B9aLnofWaJt8u1A8Idm8gpsBBYSaY3cVyeH5SWMOVPBLQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.2.tgz", + "integrity": "sha512-M91NhxqbSkI0ChkJWy69blC+rPr6HEgaeRllddSaU1pQ/7IiegeCQM9pPDIgvWnwnBSzKhUHpe6ro/jhJ+cvzw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.11.2", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz", + "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.10.tgz", + "integrity": "sha512-tFmBuZL0/v1h6eyKRgWI58ucft6dEJmAi9nhPUXoAW4ZbPSTlnsh31AuEwUoRTz+wwRk9gmgss9GZV05ZM9Kug==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.14.10", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.12.2.tgz", + "integrity": "sha512-CZJL8V10Vzibs+pDTXdQF+hot1IigIoqF4a4lA/qr5Deo1srcefiyIfgg28B67Lk7IxZhwfJMuI+1bu2xBmV0A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^2.2.0" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.4.tgz", + "integrity": "sha512-2pj8m/hnqXvMLfC0Mk+fORVTM5DQPkS6l8JpMgtoAWGVgCmYnoWdFMaNWtKbmCxBEyvMA3FlnCJyzrUSMWTfuA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.12.2", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", + "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.2.tgz", + "integrity": "sha512-iyVDGc6Vjx7Rm0cAdccLH/NG6fADsgJak/XW9IA2lPf8AjIlsemOpFGKczYyPHxm4rnKdR8z6sK4+KEC7NwmEg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.5.0.tgz", + "integrity": "sha512-G3GYHpWNJJ95502RQLApzw0jaG3pScHl+J/2MdxIuB51xtHnkRL6KvIAP3fFF1drUewWJHOnDA1U+q4Evf3KSw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.2.tgz", + "integrity": "sha512-lP96CMjMPy/+d1d9qaaHjHHdzdwvEOuyyLq9ehX89e2XMKwS1jHNzYBO+42bdSumuj5ukPbmnFtViZu8YOMT+w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.2.tgz", + "integrity": "sha512-j4A6IhVZbgxAzT6gJJC2PfOxYCK9SrDrUO7nTM4EscTYtKkAkzsbKoCnDdjFapQfnsncvPWjqVTr/0PffUwg3g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/database": "1.1.2", + "@firebase/database-types": "1.0.18", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.18.tgz", + "integrity": "sha512-yOY8IC2go9lfbVDMiy2ATun4EB2AFwocPaQADwMN/RHRUAZSM4rlAV7PGbWPSG/YhkJ2A9xQAiAENgSua9G5Fg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.15.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.13.0.tgz", + "integrity": "sha512-7i4cVNJXTMim7/P7UsNim0DwyLPk4QQ3y1oSNzv4l0ykJOKYCiFMOuEeUxUYvrReXDJxWHrT/4XMeVQm+13rRw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "@firebase/webchannel-wrapper": "1.0.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.7.tgz", + "integrity": "sha512-Et4XxtGnjp0Q9tmaEMETnY5GHJ8gQ9+RN6sSTT4ETWKmym2d6gIjarw0rCQcx+7BrWVYLEIOAXSXysl0b3xnUA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/firestore": "4.13.0", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz", + "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.3.tgz", + "integrity": "sha512-csO7ckK3SSs+NUZW1nms9EK7ckHe/1QOjiP8uAkCYa7ND18s44vjE9g3KxEeIUpyEPqZaX1EhJuFyZjHigAcYw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.7.2", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.3.tgz", + "integrity": "sha512-BxkEwWgx1of0tKaao/r2VR6WBLk/RAiyztatiONPrPE8gkitFkOnOCxf8i9cUyA5hX5RGt5H30uNn25Q6QNEmQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/functions": "0.13.3", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz", + "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.21", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.21.tgz", + "integrity": "sha512-xGFGTeICJZ5vhrmmDukeczIcFULFXybojML2+QSDFoKj5A7zbGN7KzFGSKNhDkIxpjzsYG9IleJyUebuAcmqWA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.21.tgz", + "integrity": "sha512-zahIUkaVKbR8zmTeBHkdfaVl6JGWlhVoSjF7CVH33nFqD3SlPEpEEegn2GNT5iAfsVdtlCyJJ9GW4YKjq+RJKQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz", + "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz", + "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.25.tgz", + "integrity": "sha512-7RhDwoDHlOK1/ou0/LeubxmjcngsTjDdrY/ssg2vwAVpUuVAhQzQvuCAOYxcX5wNC1zCgQ54AP1vdngBwbCmOQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.15.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.25.tgz", + "integrity": "sha512-eoOQqGLtRlseTdiemTN44LlHZpltK5gnhq8XVUuLgtIOG+odtDzrz2UoTpcJWSzaJQVxNLb/x9f39tHdDM4N4w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/messaging": "0.12.25", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz", + "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.11.tgz", + "integrity": "sha512-V3uAhrz7IYJuji+OgT3qYTGKxpek/TViXti9OSsUJ4AexZ3jQjYH5Yrn7JvBxk8MGiSLsC872hh+BxQiPZsm7g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.24", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.24.tgz", + "integrity": "sha512-YRlejH8wLt7ThWao+HXoKUHUrZKGYq+otxkPS+8nuE5PeN1cBXX7NAJl9ueuUkBwMIrnKdnDqL/voHXxDAAt3g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/performance": "0.7.11", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz", + "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.8.2.tgz", + "integrity": "sha512-5EXqOThV4upjK9D38d/qOSVwOqRhemlaOFk9vCkMNNALeIlwr+4pLjtLNo4qoY8etQmU/1q4aIATE9N8PFqg0g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/installations": "0.6.21", + "@firebase/logger": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.23.tgz", + "integrity": "sha512-4+KqRRHEUUmKT6tFmnpWATOsaFfmSuBs1jXH8JzVtMLEYqq/WS9IDM92OdefFDSrAA2xGd0WN004z8mKeIIscw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/logger": "0.5.0", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-types": "0.5.0", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz", + "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.2.tgz", + "integrity": "sha512-o/culaTeJ8GRpKXRJov21rux/n9dRaSOWLebyatFP2sqEdCxQPjVA1H9Z2fzYwQxMIU0JVmC7SPPmU11v7L6vQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.2.tgz", + "integrity": "sha512-R+aB38wxCH5zjIO/xu9KznI7fgiPuZAG98uVm1NcidHyyupGgIDLKigGmRGBZMnxibe/m2oxNKoZpfEbUX2aQQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.7.2", + "@firebase/storage": "0.14.2", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.15.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz", + "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.15.0.tgz", + "integrity": "sha512-AmWf3cHAOMbrCPG4xdPKQaj5iHnyYfyLKZxwz+Xf55bqKbpAmcYifB4jQinT2W9XhDRHISOoPyBOariJpCG6FA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz", + "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==", + "license": "Apache-2.0" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/firebase": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.11.0.tgz", + "integrity": "sha512-W9f3Y+cgQYgF9gvCGxt0upec8zwAtiQVcHuU8MfzUIgVU/9fRQWtu48Geiv1lsigtBz9QHML++Km9xAKO5GB5Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/ai": "2.10.0", + "@firebase/analytics": "0.10.21", + "@firebase/analytics-compat": "0.2.27", + "@firebase/app": "0.14.10", + "@firebase/app-check": "0.11.2", + "@firebase/app-check-compat": "0.4.2", + "@firebase/app-compat": "0.5.10", + "@firebase/app-types": "0.9.3", + "@firebase/auth": "1.12.2", + "@firebase/auth-compat": "0.6.4", + "@firebase/data-connect": "0.5.0", + "@firebase/database": "1.1.2", + "@firebase/database-compat": "2.1.2", + "@firebase/firestore": "4.13.0", + "@firebase/firestore-compat": "0.4.7", + "@firebase/functions": "0.13.3", + "@firebase/functions-compat": "0.4.3", + "@firebase/installations": "0.6.21", + "@firebase/installations-compat": "0.2.21", + "@firebase/messaging": "0.12.25", + "@firebase/messaging-compat": "0.2.25", + "@firebase/performance": "0.7.11", + "@firebase/performance-compat": "0.2.24", + "@firebase/remote-config": "0.8.2", + "@firebase/remote-config-compat": "0.2.23", + "@firebase/storage": "0.14.2", + "@firebase/storage-compat": "0.4.2", + "@firebase/util": "1.15.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7b1d96a --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "firebase": "^12.11.0" + } +} diff --git a/scratch_check_firebase.js b/scratch_check_firebase.js new file mode 100644 index 0000000..9ed61e0 --- /dev/null +++ b/scratch_check_firebase.js @@ -0,0 +1,47 @@ + +import { initializeApp } from "firebase/app"; +import { getDatabase, ref, get, child } from "firebase/database"; + +const firebaseConfig = { + apiKey: "AIzaSyDhFtqvaTMgYH9vyAHFclDUXiOxkl-2GqM", + authDomain: "silat-b3100.firebaseapp.com", + databaseURL: "https://silat-b3100-default-rtdb.firebaseio.com/", + projectId: "silat-b3100", + storageBucket: "silat-b3100.firebasestorage.app", + messagingSenderId: "471266034969", + appId: "1:471266034969:web:467de19582cf2fd3da3188" +}; + +const app = initializeApp(firebaseConfig); +const db = getDatabase(app); + +async function checkData() { + try { + const snapshot = await get(child(ref(db), 'test_history')); + if (snapshot.exists()) { + console.log("Test History Sample:"); + const data = snapshot.val(); + const firstUser = Object.keys(data)[0]; + const firstAttempt = Object.keys(data[firstUser])[0]; + console.log(JSON.stringify(data[firstUser][firstAttempt], null, 2)); + } else { + console.log("No test history found."); + } + + const userSnapshot = await get(child(ref(db), 'users')); + if (userSnapshot.exists()) { + console.log("\nCategories found:"); + const users = userSnapshot.val(); + const categories = new Set(); + Object.values(users).forEach(u => { + if (u.profile && u.profile.category) categories.add(u.profile.category); + }); + console.log(Array.from(categories)); + } + } catch (error) { + console.error(error); + } + process.exit(); +} + +checkData();