diff --git a/newclient/resultcatcher/package-lock.json b/newclient/resultcatcher/package-lock.json index e7bd6aee..96a19316 100644 --- a/newclient/resultcatcher/package-lock.json +++ b/newclient/resultcatcher/package-lock.json @@ -30,7 +30,7 @@ "rollup": ">=4.22.4", "rxjs": "~7.8.1", "tslib": "^2.3.0", - "vite": ">=5.4.6", + "vite": ">=6.0.6", "webpack": ">=5.94.0", "zone.js": "~0.15.0" }, @@ -50,8 +50,8 @@ "@types/jasmine": "~5.1.5", "@types/jasminewd2": "~2.0.13", "@types/node": "^22.10.2", - "@typescript-eslint/eslint-plugin": "8.18.2", - "@typescript-eslint/parser": "8.18.2", + "@typescript-eslint/eslint-plugin": "8.19.0", + "@typescript-eslint/parser": "8.19.0", "body-parser": ">=1.20.3", "eslint": "^9.17.0", "eslint-plugin-import": "2.31.0", @@ -68,7 +68,7 @@ "rollup": ">=4.22.4", "ts-node": "~10.9.2", "typescript": "~5.6.3", - "vite": ">=5.4.6", + "vite": ">=6.0.6", "webpack": ">=5.94.0" } }, @@ -358,639 +358,1509 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", "optional": true, + "os": [ + "android" + ], "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular-devkit/build-angular/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=8.0.0" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-2-Clause", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/open": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" - }, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@angular-devkit/build-angular/node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", "optional": true, + "os": [ + "linux" + ], "peer": true, "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=12" } }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/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, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/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/@angular-devkit/build-angular/node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/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/@angular-devkit/build-angular/node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "peer": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack": { + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1900.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1900.6.tgz", + "integrity": "sha512-WehtVrbBow4fc7hsaUKb+BZ6MDE5lO98/tgv7GR5PkRdGKnyLA0pW1AfPLJJQDgcaKjneramMhDFNc1eGSX0mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.1900.6", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/core": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.12.tgz", + "integrity": "sha512-NtB6ypsaDyPE6/fqWOdfTmACs+yK5RqfH5tStEzWFeeDsIEDYKsJ06ypuRep7qTjYus5Rmttk0Ds+cFgz8JdUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "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" + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/@angular-devkit/schematics": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.12.tgz", + "integrity": "sha512-mMea9txHbnCX5lXLHlo0RAgfhFHDio45/jMsREM2PA8UtVf2S8ltXz7ZwUrUyMQRv8vaSfn4ijDstF4hDMnRgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "18.2.12", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-19.0.2.tgz", + "integrity": "sha512-BdmMSndQt2fSBiTVniskUcUpQaeweUapbsL0IDfQ7a13vL0NVXpc3K89YXuVE/xsb08uHtqphuwxPAAj6kX3OA==", "dev": true, "license": "MIT", + "dependencies": { + "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", + "@angular-devkit/core": ">= 19.0.0 < 20.0.0" + }, "peerDependencies": { - "ajv": "^6.9.1" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" } }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/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==", + "node_modules/@angular-eslint/builder/node_modules/@angular-devkit/core": { + "version": "19.0.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.0.6.tgz", + "integrity": "sha512-WUWJhzQDsovfMY6jtb9Ktz/5sJszsaErj+XV2aXab85f1OweI/Iv2urPZnJwUSilvVN5Ok/fy3IJ6SuihK4Ceg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "node_modules/@angular-eslint/builder/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "ajv": "^8.0.0" }, - "bin": { - "webpack": "bin/webpack.js" + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@angular-eslint/builder/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">= 14.16.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-eslint/builder/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-eslint/builder/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-19.0.2.tgz", + "integrity": "sha512-HPmp92r70SNO/0NdIaIhxrgVSpomqryuUk7jszvNRtu+OzYCJGcbLhQD38T3dbBWT/AV0QXzyzExn6/2ai9fEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-19.0.2.tgz", + "integrity": "sha512-DLuNVVGGFicSThOcMSJyNje+FZSPdG0B3lCBRiqcgKH/16kfM4pV8MobPM7RGK2NhaOmmZ4zzJNwpwWPSgi+Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.0.2", + "@angular-eslint/utils": "19.0.2" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-19.0.2.tgz", + "integrity": "sha512-f/OCF9ThnxQ8m0eNYPwnCrySQPhYfCOF6STL7F9LnS8Bs3ZeW3/oT1yLaMIZ1Eg0ogIkgxksMAJZjrJPUPBD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.0.2", + "@angular-eslint/utils": "19.0.2", + "aria-query": "5.3.2", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@typescript-eslint/types": "^7.11.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-19.0.2.tgz", + "integrity": "sha512-z3rZd2sBfuYcFf9rGDsB2zz2fbGX8kkF+0ftg9eocyQmzWrlZHFmuw9ha7oP/Mz8gpblyCS/aa1U/Srs6gz0UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.0.2", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-19.0.2.tgz", + "integrity": "sha512-HotBT8OKr7zCaX1S9k27JuhRiTVIbbYVl6whlb3uwdMIPIWY8iOcEh1tjI4qDPUafpLfR72Dhwi5bO1E17F3/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.0.2" }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" } }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1900.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1900.6.tgz", - "integrity": "sha512-WehtVrbBow4fc7hsaUKb+BZ6MDE5lO98/tgv7GR5PkRdGKnyLA0pW1AfPLJJQDgcaKjneramMhDFNc1eGSX0mQ==", - "dev": true, + "node_modules/@angular/animations": { + "version": "19.0.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.0.5.tgz", + "integrity": "sha512-HCOF2CrhUvjoZWusd4nh32VOxpUrg6bV+3Z8Q36Ix3aZdni8v0qoP2rl5wGbotaPtYg5RtyDH60Z2AOPKqlrZg==", "license": "MIT", + "peer": true, "dependencies": { - "@angular-devkit/architect": "0.1900.6", - "rxjs": "7.8.1" + "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" + "@angular/core": "19.0.5" } }, - "node_modules/@angular-devkit/core": { - "version": "18.2.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.12.tgz", - "integrity": "sha512-NtB6ypsaDyPE6/fqWOdfTmACs+yK5RqfH5tStEzWFeeDsIEDYKsJ06ypuRep7qTjYus5Rmttk0Ds+cFgz8JdUQ==", + "node_modules/@angular/build": { + "version": "19.0.6", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.0.6.tgz", + "integrity": "sha512-KEVNLgTZUF2dfpOYQn+yR2HONHUTxq/2rFVhiK9qAvrm/m+uKJNEXx7hGtbRyoqenZff4ScJq+7feITUldfX8g==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1900.6", + "@babel/core": "7.26.0", + "@babel/helper-annotate-as-pure": "7.25.9", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-syntax-import-attributes": "7.26.0", + "@inquirer/confirm": "5.0.2", + "@vitejs/plugin-basic-ssl": "1.1.0", + "beasties": "0.1.0", + "browserslist": "^4.23.0", + "esbuild": "0.24.0", + "fast-glob": "3.3.2", + "https-proxy-agent": "7.0.5", + "istanbul-lib-instrument": "6.0.3", + "listr2": "8.2.5", + "magic-string": "0.30.12", + "mrmime": "2.0.0", + "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "piscina": "4.7.0", + "rollup": "4.26.0", + "sass": "1.80.7", + "semver": "7.6.3", + "vite": "5.4.11", + "watchpack": "2.4.2" }, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, + "optionalDependencies": { + "lmdb": "3.1.5" + }, "peerDependencies": { - "chokidar": "^3.5.2" + "@angular/compiler": "^19.0.0", + "@angular/compiler-cli": "^19.0.0", + "@angular/localize": "^19.0.0", + "@angular/platform-server": "^19.0.0", + "@angular/service-worker": "^19.0.0", + "@angular/ssr": "^19.0.6", + "less": "^4.2.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.5 <5.7" }, "peerDependenciesMeta": { - "chokidar": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { "optional": true } } }, - "node_modules/@angular-devkit/core/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@angular/build/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-devkit/core/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/@angular/build/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@angular-devkit/schematics": { - "version": "18.2.12", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.12.tgz", - "integrity": "sha512-mMea9txHbnCX5lXLHlo0RAgfhFHDio45/jMsREM2PA8UtVf2S8ltXz7ZwUrUyMQRv8vaSfn4ijDstF4hDMnRgQ==", + "node_modules/@angular/build/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.2.12", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.11", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "node": ">=12" } }, - "node_modules/@angular-eslint/builder": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-19.0.2.tgz", - "integrity": "sha512-BdmMSndQt2fSBiTVniskUcUpQaeweUapbsL0IDfQ7a13vL0NVXpc3K89YXuVE/xsb08uHtqphuwxPAAj6kX3OA==", + "node_modules/@angular/build/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", - "@angular-devkit/core": ">= 19.0.0 < 20.0.0" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-eslint/builder/node_modules/@angular-devkit/core": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.0.6.tgz", - "integrity": "sha512-WUWJhzQDsovfMY6jtb9Ktz/5sJszsaErj+XV2aXab85f1OweI/Iv2urPZnJwUSilvVN5Ok/fy3IJ6SuihK4Ceg==", + "node_modules/@angular/build/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "node": ">=12" } }, - "node_modules/@angular-eslint/builder/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@angular/build/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-eslint/builder/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/@angular/build/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT", "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^4.0.1" - }, + "os": [ + "linux" + ], "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=12" } }, - "node_modules/@angular-eslint/builder/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/@angular/build/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@angular-eslint/builder/node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "node_modules/@angular/build/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", "optional": true, - "peer": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "node": ">=12" } }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-19.0.2.tgz", - "integrity": "sha512-HPmp92r70SNO/0NdIaIhxrgVSpomqryuUk7jszvNRtu+OzYCJGcbLhQD38T3dbBWT/AV0QXzyzExn6/2ai9fEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-19.0.2.tgz", - "integrity": "sha512-DLuNVVGGFicSThOcMSJyNje+FZSPdG0B3lCBRiqcgKH/16kfM4pV8MobPM7RGK2NhaOmmZ4zzJNwpwWPSgi+Lw==", + "node_modules/@angular/build/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.0.2", - "@angular-eslint/utils": "19.0.2" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-19.0.2.tgz", - "integrity": "sha512-f/OCF9ThnxQ8m0eNYPwnCrySQPhYfCOF6STL7F9LnS8Bs3ZeW3/oT1yLaMIZ1Eg0ogIkgxksMAJZjrJPUPBD1Q==", + "node_modules/@angular/build/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.0.2", - "@angular-eslint/utils": "19.0.2", - "aria-query": "5.3.2", - "axobject-query": "4.1.0" - }, - "peerDependencies": { - "@typescript-eslint/types": "^7.11.0 || ^8.0.0", - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-eslint/template-parser": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-19.0.2.tgz", - "integrity": "sha512-z3rZd2sBfuYcFf9rGDsB2zz2fbGX8kkF+0ftg9eocyQmzWrlZHFmuw9ha7oP/Mz8gpblyCS/aa1U/Srs6gz0UQ==", + "node_modules/@angular/build/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.0.2", - "eslint-scope": "^8.0.2" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular-eslint/utils": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-19.0.2.tgz", - "integrity": "sha512-HotBT8OKr7zCaX1S9k27JuhRiTVIbbYVl6whlb3uwdMIPIWY8iOcEh1tjI4qDPUafpLfR72Dhwi5bO1E17F3/Q==", + "node_modules/@angular/build/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.0.2" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@angular/animations": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.0.5.tgz", - "integrity": "sha512-HCOF2CrhUvjoZWusd4nh32VOxpUrg6bV+3Z8Q36Ix3aZdni8v0qoP2rl5wGbotaPtYg5RtyDH60Z2AOPKqlrZg==", - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, + "node_modules/@angular/build/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/core": "19.0.5" + "node": ">=12" } }, - "node_modules/@angular/build": { - "version": "19.0.6", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.0.6.tgz", - "integrity": "sha512-KEVNLgTZUF2dfpOYQn+yR2HONHUTxq/2rFVhiK9qAvrm/m+uKJNEXx7hGtbRyoqenZff4ScJq+7feITUldfX8g==", + "node_modules/@angular/build/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1900.6", - "@babel/core": "7.26.0", - "@babel/helper-annotate-as-pure": "7.25.9", - "@babel/helper-split-export-declaration": "7.24.7", - "@babel/plugin-syntax-import-attributes": "7.26.0", - "@inquirer/confirm": "5.0.2", - "@vitejs/plugin-basic-ssl": "1.1.0", - "beasties": "0.1.0", - "browserslist": "^4.23.0", - "esbuild": "0.24.0", - "fast-glob": "3.3.2", - "https-proxy-agent": "7.0.5", - "istanbul-lib-instrument": "6.0.3", - "listr2": "8.2.5", - "magic-string": "0.30.12", - "mrmime": "2.0.0", - "parse5-html-rewriting-stream": "7.0.0", - "picomatch": "4.0.2", - "piscina": "4.7.0", - "rollup": "4.26.0", - "sass": "1.80.7", - "semver": "7.6.3", - "vite": "5.4.11", - "watchpack": "2.4.2" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "optionalDependencies": { - "lmdb": "3.1.5" - }, - "peerDependencies": { - "@angular/compiler": "^19.0.0", - "@angular/compiler-cli": "^19.0.0", - "@angular/localize": "^19.0.0", - "@angular/platform-server": "^19.0.0", - "@angular/service-worker": "^19.0.0", - "@angular/ssr": "^19.0.6", - "less": "^4.2.0", - "postcss": "^8.4.0", - "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=5.5 <5.7" - }, - "peerDependenciesMeta": { - "@angular/localize": { - "optional": true - }, - "@angular/platform-server": { - "optional": true - }, - "@angular/service-worker": { - "optional": true - }, - "@angular/ssr": { - "optional": true - }, - "less": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tailwindcss": { - "optional": true - } + "node": ">=12" } }, "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { @@ -1245,6 +2115,18 @@ "win32" ] }, + "node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/@angular/build/node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", @@ -1288,29 +2170,126 @@ "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.26.0", + "@rollup/rollup-android-arm64": "4.26.0", + "@rollup/rollup-darwin-arm64": "4.26.0", + "@rollup/rollup-darwin-x64": "4.26.0", + "@rollup/rollup-freebsd-arm64": "4.26.0", + "@rollup/rollup-freebsd-x64": "4.26.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.26.0", + "@rollup/rollup-linux-arm-musleabihf": "4.26.0", + "@rollup/rollup-linux-arm64-gnu": "4.26.0", + "@rollup/rollup-linux-arm64-musl": "4.26.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.26.0", + "@rollup/rollup-linux-riscv64-gnu": "4.26.0", + "@rollup/rollup-linux-s390x-gnu": "4.26.0", + "@rollup/rollup-linux-x64-gnu": "4.26.0", + "@rollup/rollup-linux-x64-musl": "4.26.0", + "@rollup/rollup-win32-arm64-msvc": "4.26.0", + "@rollup/rollup-win32-ia32-msvc": "4.26.0", + "@rollup/rollup-win32-x64-msvc": "4.26.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/@angular/build/node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/@angular/build/node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.26.0", - "@rollup/rollup-android-arm64": "4.26.0", - "@rollup/rollup-darwin-arm64": "4.26.0", - "@rollup/rollup-darwin-x64": "4.26.0", - "@rollup/rollup-freebsd-arm64": "4.26.0", - "@rollup/rollup-freebsd-x64": "4.26.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.26.0", - "@rollup/rollup-linux-arm-musleabihf": "4.26.0", - "@rollup/rollup-linux-arm64-gnu": "4.26.0", - "@rollup/rollup-linux-arm64-musl": "4.26.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.26.0", - "@rollup/rollup-linux-riscv64-gnu": "4.26.0", - "@rollup/rollup-linux-s390x-gnu": "4.26.0", - "@rollup/rollup-linux-x64-gnu": "4.26.0", - "@rollup/rollup-linux-x64-musl": "4.26.0", - "@rollup/rollup-win32-arm64-msvc": "4.26.0", - "@rollup/rollup-win32-ia32-msvc": "4.26.0", - "@rollup/rollup-win32-x64-msvc": "4.26.0", - "fsevents": "~2.3.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/@angular/cli": { @@ -3813,6 +4792,22 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", @@ -6793,17 +7788,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz", - "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz", + "integrity": "sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/type-utils": "8.18.2", - "@typescript-eslint/utils": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/scope-manager": "8.19.0", + "@typescript-eslint/type-utils": "8.19.0", + "@typescript-eslint/utils": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6822,17 +7816,75 @@ "typescript": ">=4.8.4 <5.8.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz", + "integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz", + "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz", + "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.19.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.2.tgz", - "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.0.tgz", + "integrity": "sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/scope-manager": "8.19.0", + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/typescript-estree": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0", "debug": "^4.3.4" }, "engines": { @@ -6847,15 +7899,70 @@ "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz", - "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz", + "integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz", + "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz", + "integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz", + "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2" + "@typescript-eslint/types": "8.19.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6865,15 +7972,50 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz", - "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz", + "integrity": "sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/typescript-estree": "8.19.0", + "@typescript-eslint/utils": "8.19.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6889,12 +8031,11 @@ "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz", - "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz", + "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -6903,15 +8044,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz", - "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz", + "integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -6930,43 +8070,141 @@ "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz", + "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.19.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.0.tgz", + "integrity": "sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.19.0", + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/typescript-estree": "8.19.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz", + "integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.2.tgz", - "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz", + "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz", + "integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==", "dev": true, - "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2" + "@typescript-eslint/types": "8.19.0", + "@typescript-eslint/visitor-keys": "8.19.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6976,18 +8214,16 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz", - "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz", + "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/types": "8.19.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -6998,12 +8234,20 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7011,17 +8255,19 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", - "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "MIT", + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=14.6.0" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@webassemblyjs/ast": { @@ -17611,21 +18857,20 @@ } }, "node_modules/vite": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", - "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.6.tgz", + "integrity": "sha512-NSjmUuckPmDU18bHz7QZ+bTYhRR0iA72cs2QAxCqDpafJ0S6qetco0LB3WW2OxlMHS0JmAv+yZ/R3uPmMyGTjQ==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.24.2", + "postcss": "^8.4.49", + "rollup": "^4.23.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -17634,19 +18879,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -17667,437 +18918,437 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/void-elements": { diff --git a/newclient/resultcatcher/package.json b/newclient/resultcatcher/package.json index 772a097e..094663a9 100644 --- a/newclient/resultcatcher/package.json +++ b/newclient/resultcatcher/package.json @@ -35,7 +35,7 @@ "rollup": ">=4.22.4", "rxjs": "~7.8.1", "tslib": "^2.3.0", - "vite": ">=5.4.6", + "vite": ">=6.0.6", "webpack": ">=5.94.0", "zone.js": "~0.15.0" }, @@ -55,8 +55,8 @@ "@types/jasmine": "~5.1.5", "@types/jasminewd2": "~2.0.13", "@types/node": "^22.10.2", - "@typescript-eslint/eslint-plugin": "8.18.2", - "@typescript-eslint/parser": "8.18.2", + "@typescript-eslint/eslint-plugin": "8.19.0", + "@typescript-eslint/parser": "8.19.0", "body-parser": ">=1.20.3", "eslint": "^9.17.0", "eslint-plugin-import": "2.31.0", @@ -73,7 +73,7 @@ "rollup": ">=4.22.4", "ts-node": "~10.9.2", "typescript": "~5.6.3", - "vite": ">=5.4.6", + "vite": ">=6.0.6", "webpack": ">=5.94.0" }, "description": "Resultcatcher" diff --git a/pom.xml b/pom.xml index c23f02d0..1c02dfbb 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 ch.seidel KuTu - 2.3.15 + 2.3.16 2014 @@ -330,7 +330,7 @@ 3.3.0-SNAP4 4.9.2 3.12.0 - 4.9.6 + 4.12.2 21 21 UTF-8 @@ -516,7 +516,7 @@ com.fasterxml.jackson.core jackson-databind - 2.17.0 + 2.18.2 @@ -576,7 +576,7 @@ org.apache.commons commons-text - 1.12.0 + 1.13.0 diff --git a/src/main/scala/ch/seidel/kutu/akka/CompetitionCoordinatorClientActor.scala b/src/main/scala/ch/seidel/kutu/akka/CompetitionCoordinatorClientActor.scala index 50e17b89..5dbba7bb 100644 --- a/src/main/scala/ch/seidel/kutu/akka/CompetitionCoordinatorClientActor.scala +++ b/src/main/scala/ch/seidel/kutu/akka/CompetitionCoordinatorClientActor.scala @@ -709,7 +709,7 @@ object CompetitionCoordinatorClientActor extends JsonSupport with EnrichedJson { wsSource }.named(deviceId)) - Flow.fromSinkAndSource(sink, source).log(name = deviceId) + Flow.fromSinkAndSourceCoupled(sink, source).log(name = deviceId) } // unauthenticted oneway/readonly streaming @@ -730,7 +730,7 @@ object CompetitionCoordinatorClientActor extends JsonSupport with EnrichedJson { wsSource }.named(deviceId)) - Flow.fromSinkAndSource(sink, source).log(name = deviceId) + Flow.fromSinkAndSourceCoupled(sink, source).log(name = deviceId) } } diff --git a/src/main/scala/ch/seidel/kutu/data/GroupSection.scala b/src/main/scala/ch/seidel/kutu/data/GroupSection.scala index 0c331b78..f580ffb7 100644 --- a/src/main/scala/ch/seidel/kutu/data/GroupSection.scala +++ b/src/main/scala/ch/seidel/kutu/data/GroupSection.scala @@ -24,9 +24,9 @@ object GroupSection { } def mapAvgRang(list: Iterable[(DataObject, Resultat, Resultat)]) = { - val rangD = list.toList.map(_._3.noteD).filter(_ > 0).sorted.reverse :+ 0 - val rangE = list.toList.map(_._3.noteE).filter(_ > 0).sorted.reverse :+ 0 - val rangEnd = list.toList.map(_._3.endnote).filter(_ > 0).sorted.reverse :+ 0 + val rangD = list.toList.map(_._3.noteD).filter(_ != 0).sorted.reverse :+ 0 + val rangE = list.toList.map(_._3.noteE).filter(_ != 0).sorted.reverse :+ 0 + val rangEnd = list.toList.map(_._3.endnote).filter(_ != 0).sorted.reverse :+ 0 def rang(r: Resultat) = { val rd = if (rangD.nonEmpty) rangD.indexOf(r.noteD) + 1 else 0 val re = if (rangE.nonEmpty) rangE.indexOf(r.noteE) + 1 else 0 @@ -57,17 +57,17 @@ sealed trait WKCol { case class WKLeafCol[T](override val text: String, override val prefWidth: Int, colspan: Int = 1, override val styleClass: Seq[String], valueMapper: T => String) extends WKCol case class WKGroupCol(override val text: String, override val prefWidth: Int, colspan: Int = 1, override val styleClass: Seq[String], cols: Seq[WKCol]) extends WKCol -case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable[WertungView], diszs: List[Disziplin] = List()) extends GroupSection { +case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable[WertungView], diszs: List[Disziplin] = List(), aggreateFun: TeamAggreateFun = Sum) extends GroupSection { val isTeamGroup = groupKey.isInstanceOf[Team] override val sum: Resultat = { groupKey match { - case gk: Team => gk.sum - case _ => list.map(_.resultat).reduce(_+_) + //case gk: Team => gk.sum + case _ => aggreateFun(list.map(_.resultat)) //.reduce(_+_) } } override val avg: Resultat = { groupKey match { - case gk: Team => gk.avg + case gk: Team => gk.wertungen.map(_.resultat).reduce(_ + _) / gk.wertungen.size case _ => sum / list.size } } @@ -262,7 +262,7 @@ case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable s"Total ø aus $eNoteLabel" } else { - s"ø Gerät" + "ø Gerät" } } else if (!isDivided && withDNotes) { @@ -272,16 +272,20 @@ case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable "ø Gerät" } , prefWidth = 80, styleClass = Seq("hintdata"), valueMapper = gr => { - val div = Math.max(gr.divider, divider) - if (div < 2) { - if (gr.sum.noteE > 0 - && gr.rang.noteE.toInt == 1) - "*" + gr.sum.formattedE - else - "" + gr.sum.formattedE - } - else { - (gr.sum / div).formattedEnd + if (isTeamGroup && aggreateFun != Sum) { + gr.avg.formattedEnd + } else { + val div = Math.max(gr.divider, divider) + if (div < 2) { + if (gr.sum.noteE > 0 + && gr.rang.noteE.toInt == 1) + "*" + gr.sum.formattedE + else + "" + gr.sum.formattedE + } + else { + (gr.sum / div).formattedEnd + } } } ), @@ -308,18 +312,18 @@ case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable def mapToAvgRowSummary(athlWertungen: Iterable[WertungView] = list): (Resultat, Resultat, Iterable[(Disziplin, Long, Resultat, Resultat, Option[Int], Option[BigDecimal])], Iterable[(ProgrammView, Resultat, Resultat, Option[Int], Option[BigDecimal])], Resultat) = { val wks = athlWertungen.filter(_.endnote.nonEmpty).groupBy { w => w.wettkampf } - val wksums = wks.map { wk => wk._2.map(w => w.resultat).reduce(_ + _) }.toList - val rsum = if (wksums.nonEmpty) wksums.reduce(_ + _) else Resultat(0, 0, 0) + val wksums = wks.map { wk => aggreateFun(wk._2.map(w => w.resultat)) }.toList + val rsum = aggreateFun(wksums) - val gwksums = wks.map { wk => + val gwksums = wks.map { wk => aggreateFun( wk._2.map { w => if (anzahWettkaempfe > 1) w.resultat else (w.resultat * STANDARD_SCORE_FACTOR) + (w.resultat * gleichstandsregel.factorize(w, wk._2.map(w => w.resultat).toList)) - }.reduce(_ + _) + }) * aggreateFun.sortFactor } - val gsum = if (gwksums.nonEmpty) gwksums.reduce(_ + _) else Resultat(0, 0, 0) + val gsum = aggreateFun(gwksums) //if (gwksums.nonEmpty) gwksums.reduce(_ + _) else Resultat(0, 0, 0) val avg = if (wksums.nonEmpty) rsum / wksums.size else Resultat(0, 0, 0) val gavg = if (wksums.nonEmpty) gsum / wksums.size else Resultat(0, 0, 0) val withAuszeichnung = anzahWettkaempfe == 1 && groups.size == 1 && wks.size == 1 @@ -332,11 +336,12 @@ case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable yield { val prog = dwertungen.head.wettkampf.programmId val dsums = dwertungen.map { w => w.resultat } - val dsum = if (dsums.nonEmpty) dsums.reduce(_ + _) else Resultat(0, 0, 0) + val dsum = aggreateFun(dsums)// if (dsums.nonEmpty) dsums.reduce(_ + _) else Resultat(0, 0, 0) ((ord, disziplin, prog) -> dsum) }).groupBy(_._1).map { x => val xsum = x._2.map(_._2).reduce(_ + _) - (x._1, xsum, xsum / x._2.size, auszeichnung, auszeichnungEndnote) + val xasum = aggreateFun(x._2.map(_._2)) + (x._1, xasum, xsum / x._2.size, auszeichnung, auszeichnungEndnote) } .toList.sortBy(d => d._1._1) .map(d => (d._1._2, d._1._3, d._2, d._3, d._4, d._5)) @@ -347,13 +352,14 @@ case class GroupLeaf[GK <: DataObject](override val groupKey: GK, list: Iterable _.wettkampfdisziplin.programm.aggregatorSubHead } psums = pwertungen.map { w => w.resultat } - psum = if (psums.nonEmpty) psums.reduce(_ + _) else Resultat(0, 0, 0) + psum = aggreateFun(psums) //if (psums.nonEmpty) psums.reduce(_ + _) else Resultat(0, 0, 0) } yield { (programm, psum) }).groupBy(_._1).map { x => val xsum = x._2.map(_._2).reduce(_ + _) - (x._1, xsum, xsum / x._2.size, auszeichnung, auszeichnungEndnote) + val xasum = aggreateFun(x._2.map(_._2)) + (x._1, xasum, xsum / x._2.size, auszeichnung, auszeichnungEndnote) } .toList.sortBy(d => d._1.ord) (rsum, avg, perDisziplinAvgs, perProgrammAvgs, gavg) @@ -497,7 +503,7 @@ object TeamSums { val diszs = teams.flatMap(_.diszList).distinct .groupBy(_._1).toList.sortBy(_._2.head._2).map(_._2.head._1) val tms = teams.filter(team => team.wertungen.nonEmpty).map { team => - GroupLeaf(team, team.wertungen, diszs) + GroupLeaf(team, team.wertungen, diszs, team.aggregateFun) } if (tms.isEmpty) None else Some(TeamSums(teamRows.groupKey.asInstanceOf[DataObject], tms)) } @@ -508,8 +514,12 @@ object TeamSums { } case class TeamSums(override val groupKey: DataObject, teamRows: List[GroupLeaf[Team]]) extends GroupSection { + /** + * used to filter teams in scores, only if they've results. Therefore, the aggregateFn isn't relevant for that. + */ override val sum: Resultat = teamRows.map(_.sum).reduce(_ + _) override val avg: Resultat = sum / teamRows.size + def getTeam(gl: GroupLeaf[Team]) = gl.groupKey def getTeamGroupLeaf(team: Team): GroupLeaf[Team] = teamRows.find(t => t.groupKey.equals(team)).get @@ -544,7 +554,8 @@ case class TeamSums(override val groupKey: DataObject, teamRows: List[GroupLeaf[ (getTeam(x), x) }.map { x => val (team, teamRow) = x - (team, teamRow.mapToAvgRowSummary(team.countingWertungen.flatMap(_._2))) + val teamwertungen = team.countingWertungen.flatMap(_._2) + (team, teamRow.mapToAvgRowSummary(teamwertungen)) } (for (teamRuleGroup <- avgPerTeams.groupBy(_._1.rulename)) yield { @@ -571,11 +582,11 @@ case class TeamSums(override val groupKey: DataObject, teamRows: List[GroupLeaf[ } avgPerTeam.map { x => - val (team, (sum, avg, wd, wp, gsum)) = x + val (team, (sum, teamTotalScore, wd, wp, gsum)) = x val gsrang = rangMap(team) val gs = mapToTeamSum(team, wd) - TeamRow(team, gs, avg, gsrang.rang, + TeamRow(team, gs, teamTotalScore, gsrang.rang, gsrang.rang.endnote > 0 && gsrang.rang.endnote < 4 ) diff --git a/src/main/scala/ch/seidel/kutu/domain/TeamRegel.scala b/src/main/scala/ch/seidel/kutu/domain/TeamRegel.scala index 0355c584..d5d081ab 100644 --- a/src/main/scala/ch/seidel/kutu/domain/TeamRegel.scala +++ b/src/main/scala/ch/seidel/kutu/domain/TeamRegel.scala @@ -17,26 +17,31 @@ object TeamRegel { , ("Aus Verein, drei Bestnoten pro Gerät, mit max vier Mitglieder, zusammengefasste Kategorien K6, K7, KH, KD" -> s"$vereinGeraet[K6+K7+KD+KH](3/4)") , ("Aus Verein, drei Gesamt-Bestnoten, mit unbeschränkter Anzahl Mitglieder" -> s"$vereinGesamt(3/*)") , ("Aus Verein, drei Gesamt-Bestnoten, mit max vier Mitglieder" -> s"$vereinGesamt(3/4)") + , ("Aus Verein, durchschnitt pro Gerät, mit unbeschränkter Anzahl Mitglieder (M/W)" -> s"$vereinGeraet[M+W](avg/*/*)") + , ("Aus Verein, median pro Gerät, mit unbeschränkter Anzahl Mitglieder (M/W)" -> s"$vereinGeraet[M+W](median/*/*)") + , ("Aus Verein, kleinste Abweichung pro Gerät, mit unbeschränkter Anzahl Mitglieder (M/W)" -> s"$vereinGeraet[M+W](devmin/*/*)") + , ("Aus Verein, grösste Abweichung pro Gerät, mit unbeschränkter Anzahl Mitglieder (M/W)" -> s"$vereinGeraet[M+W](devmax/*/*)") , ("Aus Verband, drei Bestnoten pro Gerät, mit unbeschränkter Anzahl Mitglieder" -> s"$verbandGeraet(3/*)") , ("Aus Verband, drei Bestnoten pro Gerät, mit max vier Mitglieder" -> s"$verbandGeraet(3/4)") , ("Aus Verband, drei Gesamt-Bestnoten, mit unbeschränkter Anzahl Mitglieder" -> s"$verbandGesamt(3/*)") , ("Aus Verband, drei Gesamt-Bestnoten, mit max vier Mitglieder" -> s"$verbandGesamt(3/4)") , ("Individuell" -> s"$vereinGesamt(//+), $verbandGesamt(/), VereinGerät(/), $vereinGeraet(/)") ) - private val rangePattern = "([a-zA-ZäöüÄÖÜ]+)([\\[\\S\\s0-9+\\]]+)?\\(([0-9]+)\\/([0-9,\\*]*)(\\/[\\S\\s\\/0-9+]*)?\\)".r + private val rangePattern = "([a-zA-ZäöüÄÖÜ]+)([\\[\\S\\s0-9+\\]]+)?\\(([devmax\\/|devmin\\/|median\\/|min\\/|max\\/|avg\\/|sum\\/]+)?([0-9,\\*]+)\\/([0-9,\\*]*)(\\/[\\S\\s\\/0-9+]*)?\\)".r def apply(formel: String): TeamRegel = { - def defaultMax(max: String): Int = if (max.equals("*")) 0 else max + def default(cnt: String): Int = if (cnt.equals("*")) 0 else try cnt.intValue catch {case _ => 0} val regeln = formel.split(",").map(_.trim).filter(_.nonEmpty).toList val mappedRules: List[TeamRegel] = regeln.flatMap { - case rangePattern(rulename, grouper, min, max, extrateams) => + case rangePattern(rulename, grouper, aggFn, min, max, extrateams) => + val aggFun = TeamAggreateFun(aggFn) val extraTeamsDef = if (extrateams == null) "" else extrateams val grouperDef = if (grouper == null) "" else grouper rulename match { - case `vereinGesamt` => Some(TeamRegelVereinGesamt(min, defaultMax(max), extraTeamsDef, grouperDef)) - case `verbandGesamt` => Some(TeamRegelVerbandGesamt(min, defaultMax(max), extraTeamsDef, grouperDef)) - case `vereinGeraet` => Some(TeamRegelVereinGeraet(min, defaultMax(max), extraTeamsDef, grouperDef)) - case `verbandGeraet` => Some(TeamRegelVerbandGeraet(min, defaultMax(max), extraTeamsDef, grouperDef)) + case `vereinGesamt` => Some(TeamRegelVereinGesamt(default(min), default(max), extraTeamsDef, grouperDef, aggFun)) + case `verbandGesamt` => Some(TeamRegelVerbandGesamt(default(min), default(max), extraTeamsDef, grouperDef, aggFun)) + case `vereinGeraet` => Some(TeamRegelVereinGeraet(default(min), default(max), extraTeamsDef, grouperDef, aggFun)) + case `verbandGeraet` => Some(TeamRegelVerbandGeraet(default(min), default(max), extraTeamsDef, grouperDef, aggFun)) case _ => None } case "Keine Teams" =>None @@ -80,11 +85,12 @@ sealed trait TeamRegel { * Per rule means, that each rule can have its own definition about whether a split or a group of a criterion is required. * @param wertungen list of wertungen, containing athlets and its assignment to a program, team, etc., where each * rule can extract its criterion to apply a splitting- or grouping- rule. - * @return + * @return List[pgm,sex,List[teams]] */ def extractTeamsWithDefaultGouping(wertungen: Iterable[WertungView]): List[(String,String,List[Team])] = { + val hasNoExplicitTeams = !wertungen.exists(w => w.team != 0) wertungen - .filter(w => w.team != 0) + .filter(w => hasNoExplicitTeams || w.team != 0) .toList .groupBy(w => (pgmGrouperText(w), sexGrouperText(w))) .map( gr => (gr._1._1, gr._1._2, extractTeams(gr._2))) @@ -114,41 +120,43 @@ case class TeamRegelList(regeln: List[TeamRegel], name: Option[String] = None) e override def toRuleName: String = name.getOrElse(regeln.map(_.toRuleName).sorted.mkString(", ")) } -case class TeamRegelVereinGeraet(min: Int, max: Int, extraTeamsDef: String, grouperDef: String) extends TeamRegel { +case class TeamRegelVereinGeraet(min: Int, max: Int, extraTeamsDef: String, grouperDef: String, aggregateFun: TeamAggreateFun) extends TeamRegel { private val extrateams = parseExtrateams(extraTeamsDef) override def getExtrateams: List[String] = extrateams private val grouperDefs = parseGrouperDefs(grouperDef) override def getGrouperDefs: List[Set[String]] = grouperDefs - override def toFormel: String = s"VereinGerät$grouperDef($min/${if (max > 0) max else "*"}$extraTeamsDef)" - override def toRuleName: String = s"""Vereins-Team Rangliste $grouperDef (beste $min Gerätewertungen${if (max > 0) s" aus $max" else ""})""" + override def toFormel: String = s"VereinGerät$grouperDef(${aggregateFun.toFormelPart}${if (min > 0) min else "*"}/${if (max > 0) max else "*"}$extraTeamsDef)" + override def toRuleName: String = s"""Vereins-Team Rangliste $grouperDef (${aggregateFun.toDescriptionPart} ${if (min == 0) "allen" else s"besten $min"}${if (max > 0) s" von max $max" else ""} Gerätewertungen)""" override def extractTeams(wertungen: Iterable[WertungView]): List[Team] = { val extraTeams = extractExtraTeams(wertungen) + val hasNoExplicitTeams = !wertungen.exists(w => w.team != 0) wertungen - .filter(w => w.team != 0) + .filter(w => hasNoExplicitTeams || w.team != 0) .toList .groupBy(w => w.getTeamName(extraTeams)) .flatMap { team => val (teamname, teamwertungen) = team val athletCount = teamwertungen.map(w => w.athlet.id).toSet.size - if (athletCount >= min && (max == 0 || athletCount <= max)) { + if (((min == 0 && athletCount > 0) || athletCount >= min) && (max == 0 || athletCount <= max)) { + val takeCnt = if (min == 0) athletCount else min val perDisciplinWertungen: Map[Disziplin, List[WertungView]] = teamwertungen .groupBy(w => w.wettkampfdisziplin.disziplin) .flatMap { case (disciplin, wtgs) => val relevantDisciplineValues = wtgs - .filter(_.resultat.endnote > 0) + //.filter(_.resultat.endnote > 0) .groupBy(_.resultat.endnote).toList - .sortBy(_._1).reverse.take(min) + .sortBy(_._1).reverse.take(takeCnt) .flatMap(_._2) if (relevantDisciplineValues.isEmpty) None else Some((disciplin, relevantDisciplineValues)) } val perDisciplinCountingWertungen: Map[Disziplin, List[WertungView]] = perDisciplinWertungen .flatMap { case (disciplin, wtgs) => val relevantDisciplineValues = wtgs - .filter(_.resultat.endnote > 0) - .sortBy(_.resultat.endnote).reverse.take(min) + //.filter(_.resultat.endnote > 0) + .sortBy(_.resultat.endnote).reverse.take(takeCnt) if (relevantDisciplineValues.isEmpty) None else Some((disciplin, relevantDisciplineValues)) } val limitedTeamwertungen = if (max > 0) teamwertungen else { @@ -157,7 +165,7 @@ case class TeamRegelVereinGeraet(min: Int, max: Int, extraTeamsDef: String, grou allRelevantWertungen.contains(w.athlet) } } - List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perDisciplinCountingWertungen, perDisciplinWertungen)) + List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perDisciplinCountingWertungen, perDisciplinWertungen, aggregateFun)) } else { List.empty } @@ -166,27 +174,29 @@ case class TeamRegelVereinGeraet(min: Int, max: Int, extraTeamsDef: String, grou override def teamsAllowed: Boolean = true } -case class TeamRegelVereinGesamt(min: Int, max: Int, extraTeamsDef: String, grouperDef: String) extends TeamRegel { +case class TeamRegelVereinGesamt(min: Int, max: Int, extraTeamsDef: String, grouperDef: String, aggregateFun: TeamAggreateFun) extends TeamRegel { private val extrateams = parseExtrateams(extraTeamsDef) override def getExtrateams: List[String] = extrateams private val grouperDefs = parseGrouperDefs(grouperDef) override def getGrouperDefs: List[Set[String]] = grouperDefs - override def toFormel: String = s"VereinGesamt$grouperDef($min/${if (max > 0) max else "*"}$extraTeamsDef)" + override def toFormel: String = s"VereinGesamt$grouperDef(${aggregateFun.toFormelPart}${if (min > 0) min else "*"}/${if (max > 0) max else "*"}$extraTeamsDef)" - override def toRuleName: String = s"""Vereins-Team Rangliste $grouperDef (beste $min Gesamtwertungen${if (max > 0) s" aus $max" else ""})""" + override def toRuleName: String = s"""Vereins-Team Rangliste $grouperDef (${aggregateFun.toDescriptionPart} ${if (min == 0) "allen" else s"besten $min"}${if (max > 0) s" von max $max" else ""} Gesamtwertungen)""" override def extractTeams(wertungen: Iterable[WertungView]): List[Team] = { val extraTeams = extractExtraTeams(wertungen) + val hasNoExplicitTeams = !wertungen.exists(w => w.team != 0) wertungen - .filter(w => w.team != 0) + .filter(w => hasNoExplicitTeams || w.team != 0) .toList .groupBy(w => w.getTeamName(extraTeams)) .flatMap { team => val (teamname, teamwertungen) = team val athletCount = teamwertungen.map(w => w.athlet.id).toSet.size - if (athletCount >= min && (max == 0 || athletCount <= max)) { + if (((min == 0 && athletCount > 0) || athletCount >= min) && (max == 0 || athletCount <= max)) { + val takeCnt = if (min == 0) athletCount else min val perAthletWertungen = teamwertungen .groupBy(w => w.athlet) .map{ case (athlet, wtgs) => @@ -194,7 +204,7 @@ case class TeamRegelVereinGesamt(min: Int, max: Int, extraTeamsDef: String, grou (athlet, wtgs, wtgsum) } .toList - .sortBy(_._3).reverse.take(min) // sortiert auf Gesamtresultat + .sortBy(_._3).reverse.take(takeCnt) // sortiert auf Gesamtresultat .flatMap(_._2) // mit wertungen die Disziplin-Map aufbauen .groupBy(w => w.wettkampfdisziplin.disziplin) val limitedTeamwertungen = if (max > 0) teamwertungen else { @@ -203,7 +213,7 @@ case class TeamRegelVereinGesamt(min: Int, max: Int, extraTeamsDef: String, grou allRelevantWertungen.contains } } - List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perAthletWertungen, perAthletWertungen)) + List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perAthletWertungen, perAthletWertungen, aggregateFun)) } else { List.empty } @@ -213,42 +223,44 @@ case class TeamRegelVereinGesamt(min: Int, max: Int, extraTeamsDef: String, grou override def teamsAllowed: Boolean = true } -case class TeamRegelVerbandGeraet(min: Int, max: Int, extraTeamsDef: String, grouperDef: String) extends TeamRegel { +case class TeamRegelVerbandGeraet(min: Int, max: Int, extraTeamsDef: String, grouperDef: String, aggregateFun: TeamAggreateFun) extends TeamRegel { private val extrateams = parseExtrateams(extraTeamsDef) override def getExtrateams: List[String] = extrateams private val grouperDefs = parseGrouperDefs(grouperDef) override def getGrouperDefs: List[Set[String]] = grouperDefs - override def toFormel: String = s"VerbandGerät$grouperDef($min/${if (max > 0) max else "*"}$extraTeamsDef)" + override def toFormel: String = s"VerbandGerät$grouperDef(${aggregateFun.toFormelPart}${if (min > 0) min else "*"}/${if (max > 0) max else "*"}$extraTeamsDef)" - override def toRuleName: String = s"""Verbands-Team Rangliste $grouperDef (beste $min Gerätewertungen${if (max > 0) s" aus $max" else ""})""" + override def toRuleName: String = s"""Verbands-Team Rangliste $grouperDef (${aggregateFun.toDescriptionPart} ${if (min == 0) "allen" else s"besten $min"}${if (max > 0) s" von max $max" else ""} Gerätewertungen)""" override def extractTeams(wertungen: Iterable[WertungView]): List[Team] = { val extraTeams = extractExtraTeams(wertungen) + val hasNoExplicitTeams = !wertungen.exists(w => w.team != 0) wertungen - .filter(w => w.team != 0) + .filter(w => hasNoExplicitTeams || w.team != 0) .toList .groupBy(w => w.getTeamName(extraTeams)) .flatMap { team => val (teamname, teamwertungen) = team val athletCount = teamwertungen.map(w => w.athlet.id).toSet.size - if (athletCount >= min && (max == 0 || athletCount <= max)) { + if (((min == 0 && athletCount > 0) || athletCount >= min) && (max == 0 || athletCount <= max)) { + val takeCnt = if (min == 0) athletCount else min val perDisciplinWertungen: Map[Disziplin, List[WertungView]] = teamwertungen .groupBy(w => w.wettkampfdisziplin.disziplin) .flatMap { case (disciplin, wtgs) => val relevantDisciplineValues = wtgs - .filter(_.resultat.endnote > 0) + //.filter(_.resultat.endnote > 0) .groupBy(_.resultat.endnote).toList - .sortBy(_._1).reverse.take(min) + .sortBy(_._1).reverse.take(takeCnt) .flatMap(_._2) if (relevantDisciplineValues.isEmpty) None else Some((disciplin, relevantDisciplineValues)) } val perDisciplinCountingWertungen: Map[Disziplin, List[WertungView]] = perDisciplinWertungen .flatMap { case (disciplin, wtgs) => val relevantDisciplineValues = wtgs - .filter(_.resultat.endnote > 0) - .sortBy(_.resultat.endnote).reverse.take(min) + //.filter(_.resultat.endnote > 0) + .sortBy(_.resultat.endnote).reverse.take(takeCnt) if (relevantDisciplineValues.isEmpty) None else Some((disciplin, relevantDisciplineValues)) } val limitedTeamwertungen = if (max > 0) teamwertungen else { @@ -258,7 +270,7 @@ case class TeamRegelVerbandGeraet(min: Int, max: Int, extraTeamsDef: String, gro allRelevantWertungen.contains(w.athlet) } } - List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perDisciplinCountingWertungen, perDisciplinWertungen)) + List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perDisciplinCountingWertungen, perDisciplinWertungen, aggregateFun)) } else { List.empty } @@ -267,26 +279,28 @@ case class TeamRegelVerbandGeraet(min: Int, max: Int, extraTeamsDef: String, gro override def teamsAllowed: Boolean = true } -case class TeamRegelVerbandGesamt(min: Int, max: Int, extraTeamsDef: String, grouperDef: String) extends TeamRegel { +case class TeamRegelVerbandGesamt(min: Int, max: Int, extraTeamsDef: String, grouperDef: String, aggregateFun: TeamAggreateFun) extends TeamRegel { private val extrateams = parseExtrateams(extraTeamsDef) override def getExtrateams: List[String] = extrateams private val grouperDefs = parseGrouperDefs(grouperDef) override def getGrouperDefs: List[Set[String]] = grouperDefs - override def toFormel: String = s"VerbandGesamt$grouperDef($min/${if (max > 0) max else "*"}$extraTeamsDef)" - override def toRuleName: String = s"""Verbands-Team Rangliste $grouperDef (beste $min Gesamtwertungen${if (max > 0) s" aus $max" else ""})""" + override def toFormel: String = s"VerbandGesamt$grouperDef(${aggregateFun.toFormelPart}${if (min > 0) min else "*"}/${if (max > 0) max else "*"}$extraTeamsDef)" + override def toRuleName: String = s"""Verbands-Team Rangliste $grouperDef (${aggregateFun.toDescriptionPart} ${if (min == 0) "allen" else s"besten $min"}${if (max > 0) s" von max $max" else ""} Gesamtwertungen)""" override def extractTeams(wertungen: Iterable[WertungView]): List[Team] = { val extraTeams = extractExtraTeams(wertungen) + val hasNoExplicitTeams = !wertungen.exists(w => w.team != 0) wertungen - .filter(w => w.team != 0) + .filter(w => hasNoExplicitTeams || w.team != 0) .toList .groupBy(w => w.getTeamName(extraTeams)) .flatMap { team => val (teamname, teamwertungen) = team val athletCount = teamwertungen.map(w => w.athlet.id).toSet.size - if (athletCount >= min && (max == 0 || athletCount <= max)) { + if (((min == 0 && athletCount > 0) || athletCount >= min) && (max == 0 || athletCount <= max)) { + val takeCnt = if (min == 0) athletCount else min val perAthletWertungen = teamwertungen .groupBy(w => w.athlet) .map{ case (athlet, wtgs) => @@ -294,7 +308,7 @@ case class TeamRegelVerbandGesamt(min: Int, max: Int, extraTeamsDef: String, gro (athlet, wtgs, wtgsum) } .toList - .sortBy(_._3).reverse.take(min) // sortiert auf Gesamtresultat + .sortBy(_._3).reverse.take(takeCnt) // sortiert auf Gesamtresultat .flatMap(_._2) // mit wertungen die Disziplin-Map aufbauen .groupBy(w => w.wettkampfdisziplin.disziplin) val limitedTeamwertungen = if (max > 0) teamwertungen else { @@ -303,7 +317,7 @@ case class TeamRegelVerbandGesamt(min: Int, max: Int, extraTeamsDef: String, gro allRelevantWertungen.contains } } - List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perAthletWertungen, perAthletWertungen)) + List(Team(s"${teamname}", toRuleName, limitedTeamwertungen, perAthletWertungen, perAthletWertungen, aggregateFun)) } else { List.empty } diff --git a/src/main/scala/ch/seidel/kutu/domain/package.scala b/src/main/scala/ch/seidel/kutu/domain/package.scala index 17a2fe8d..2b2f026a 100644 --- a/src/main/scala/ch/seidel/kutu/domain/package.scala +++ b/src/main/scala/ch/seidel/kutu/domain/package.scala @@ -10,10 +10,11 @@ import java.net.URLEncoder import java.nio.file.{Files, LinkOption, Path, StandardOpenOption} import java.sql.{Date, Timestamp} import java.text.{ParseException, SimpleDateFormat} -import java.time.{LocalDate, LocalDateTime, LocalTime, Period, ZoneId} +import java.time._ import java.util.UUID import java.util.concurrent.TimeUnit import scala.concurrent.duration.Duration +import scala.math.BigDecimal.RoundingMode package object domain { implicit def dbl2Str(d: Double): String = f"${d}%2.3f" @@ -93,7 +94,7 @@ package object domain { Integer.parseInt(c) true } catch { - case _:NumberFormatException => false + case _: NumberFormatException => false } } @@ -198,6 +199,7 @@ package object domain { val ep = easyprint if (ep.matches(".*\\s,\\.;.*")) s""""$ep"""" else ep } + def compare(o: DataObject): Int = easyprint.compare(o.easyprint) } @@ -226,12 +228,15 @@ package object domain { case class CompoundGrouper(groupers: Seq[DataObject]) extends DataObject { //GenericGrouper(groupers.map(_.easyprint).mkString(",")) override def easyprint: String = groupers.map(_.easyprint).mkString(",") } + case class GenericGrouper(name: String) extends DataObject { override def easyprint: String = name } case class TurnerGeschlecht(geschlecht: String) extends DataObject { override def easyprint = geschlecht.toLowerCase() match { + case "m,w" => "TuTi" + case "w,m" => "TuTi" case "m" => "Turner" case "w" => "Turnerinnen" case "f" => "Turnerinnen" @@ -347,7 +352,116 @@ package object domain { def updatedWith(athlet: Athlet) = AthletView(athlet.id, athlet.js_id, athlet.geschlecht, athlet.name, athlet.vorname, athlet.gebdat, athlet.strasse, athlet.plz, athlet.ort, verein.map(v => v.copy(id = athlet.verein.getOrElse(0L))), athlet.activ) } - case class Team(name: String, rulename: String, wertungen: List[WertungView], countingWertungen: Map[Disziplin, List[WertungView]], relevantWertungen: Map[Disziplin, List[WertungView]]) extends DataObject { + object TeamAggreateFun { + def apply(text: String): TeamAggreateFun = { + if (text == null) Sum else text.toLowerCase() match { + case "avg/" => Avg + case "median/" => Med + case "min/" => Min + case "max/" => Max + case "devmin/" => DevMin + case "devmax/" => DevMax + case _ => Sum + } + } + } + + sealed trait TeamAggreateFun { + def sum(xs: Iterable[Resultat]): Resultat = if (xs.nonEmpty) xs.reduce(_ + _) else Resultat(0, 0, 0) + def max(xs: Iterable[Resultat]): Resultat = if (xs.nonEmpty) xs.reduce(_.max(_)) else Resultat(0, 0, 0) + def min(xs: Iterable[Resultat]): Resultat = if (xs.nonEmpty) xs.reduce(_.min(_)) else Resultat(0, 0, 0) + def mean(xs: Iterable[Resultat]): Resultat = if (xs.nonEmpty) sum(xs) / xs.size else Resultat(0, 0, 0) + def median(xs: Iterable[Resultat]): Resultat = xs match { + case Nil => Resultat(0,0,0) + case x::Nil => x + case _ => + val l = xs.toList.sortBy(_.endnote) + val i = Math.max(1, l.size / 2) + if (l.size % 2 == 0) { + (l(i-1) + l(i)) / 2 + } else { + l(i) + } + } + + def variance(xs: Iterable[Resultat]): Resultat = { + if (xs.nonEmpty) { + val avg = mean(xs) + + mean(xs + .map(_ - avg) + .map(_.pow(2)) + ) + } else Resultat(0, 0, 0) + } + + def stdDev(xs: Iterable[Resultat]): Resultat = xs match { + case Nil => Resultat(0,0,0) + case x::Nil => x + case _ => variance(xs).sqrt + } + + def apply(results: Iterable[Resultat]): Resultat + def sortFactor = 1 + def toFormelPart: String = "" + + def toDescriptionPart: String + } + + case object Sum extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = sum(results) + + def toDescriptionPart: String = "Summe aus" + } + + case object Avg extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = mean(results) + + override def toFormelPart: String = "avg/" + + def toDescriptionPart: String = "⌀ aus" + } + + case object Med extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = median(results) + + override def toFormelPart: String = "median/" + + def toDescriptionPart: String = "Median aus" + } + + case object Max extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = max(results) + + override def toFormelPart: String = "max/" + + def toDescriptionPart: String = "höchste aus" + } + + case object Min extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = min(results) + + override def toFormelPart: String = "min/" + + def toDescriptionPart: String = "niedrigste aus" + } + + case object DevMin extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = stdDev(results) + override def sortFactor = -1 + override def toFormelPart: String = "devmin/" + + def toDescriptionPart: String = "kleinste Abweichung aus" + } + + case object DevMax extends TeamAggreateFun { + override def apply(results: Iterable[Resultat]): Resultat = stdDev(results) + override def toFormelPart: String = "devmax/" + + def toDescriptionPart: String = "grösste Abweichung aus" + } + + case class Team(name: String, rulename: String, wertungen: List[WertungView], countingWertungen: Map[Disziplin, List[WertungView]], relevantWertungen: Map[Disziplin, List[WertungView]], aggregateFun: TeamAggreateFun) extends DataObject { val diszList: Map[Disziplin, Int] = countingWertungen.map { t => val disz = t._1 val ord = t._2.find(_.wettkampfdisziplin.disziplin == t._1).map(_.wettkampfdisziplin.ord).getOrElse(999) @@ -355,18 +469,20 @@ package object domain { } val perDisciplinResults: Map[Disziplin, List[Resultat]] = countingWertungen - .map{ case (disciplin, wtg) => (disciplin, wtg - .map(w => if (w.showInScoreList) w.resultat else Resultat(0,0,0))) + .map { case (disciplin, wtg) => (disciplin, wtg + .map(w => if (w.showInScoreList) w.resultat else Resultat(0, 0, 0))) } - val perDisciplinSums = perDisciplinResults.map{ case (disciplin, results) => (disciplin, results.reduce(_+_)) } - val sum = if (perDisciplinSums.values.nonEmpty) perDisciplinSums.values.reduce(_+_) else Resultat(0,0,0) - val avg = if (perDisciplinSums.values.nonEmpty) sum / perDisciplinResults.keySet.size else Resultat(0,0,0) + //val perDisciplinSums = perDisciplinResults.map{ case (disciplin, results) => (disciplin, aggregateFun(results)) } + //val sum = aggregateFun(perDisciplinSums.values) + //val avg = Avg(perDisciplinSums.values) val blockrows = wertungen.map(_.athlet).distinct.size + def isRelevantResult(disziplin: Disziplin, member: AthletView): Boolean = { relevantWertungen(disziplin).find(_.athlet.equals(member)).exists(w => perDisciplinResults(disziplin).exists(r => r.endnote.equals(w.resultat.endnote))) } + override def easyprint: String = "Team " + name } @@ -382,7 +498,7 @@ package object domain { case _ => false } } - + object Wertungsrichter { def apply(): Wertungsrichter = Wertungsrichter(0, 0, "", "", "", None, "", "", "", None, activ = true) } @@ -446,13 +562,17 @@ package object domain { case class SimpleDurchgang(id: Long, wettkampfId: Long, title: String, name: String, durchgangtype: DurchgangType, ordinal: Int, planStartOffset: Long, effectiveStartTime: Option[java.sql.Timestamp], effectiveEndTime: Option[java.sql.Timestamp]) extends DataObject { override def easyprint = if (name.equals(title)) name else s"$title: $name" + def effectivePlanStart(wkDate: LocalDate): LocalDateTime = LocalDateTime.of(wkDate, LocalTime.MIDNIGHT).plusNanos(planStartOffset * 1000_000L) } case class Durchgang(id: Long, wettkampfId: Long, title: String, name: String, durchgangtype: DurchgangType, ordinal: Int, planStartOffset: Long, effectiveStartTime: Option[java.sql.Timestamp], effectiveEndTime: Option[java.sql.Timestamp], planEinturnen: Long, planGeraet: Long, planTotal: Long) extends DataObject { override def easyprint = if (name.equals(title)) name else s"$title: $name" + def effectivePlanStart(wkDate: LocalDate): LocalDateTime = LocalDateTime.of(wkDate, LocalTime.MIDNIGHT).plusNanos(planStartOffset * 1000_000L) - def effectivePlanFinish(wkDate: LocalDate): LocalDateTime = LocalDateTime.of(wkDate, LocalTime.MIDNIGHT).plusNanos((planStartOffset + (if (planStartOffset > 0) planTotal else 24000*3600)) * 1000_000L) + + def effectivePlanFinish(wkDate: LocalDate): LocalDateTime = LocalDateTime.of(wkDate, LocalTime.MIDNIGHT).plusNanos((planStartOffset + (if (planStartOffset > 0) planTotal else 24000 * 3600)) * 1000_000L) + def toAggregator(other: Durchgang) = Durchgang(0, wettkampfId, title, title, durchgangtype, Math.min(ordinal, other.ordinal), Math.min(planStartOffset, planStartOffset), effectiveStartTime, effectiveEndTime, Math.max(planEinturnen, other.planEinturnen), Math.max(planGeraet, other.planGeraet), Math.max(planTotal, other.planTotal)) } @@ -483,26 +603,27 @@ package object domain { "Kür", "LK1", "LK2", "LK3", "LK4" ) } + object Altersklasse { // file:///C:/Users/Roland/Downloads/Turn10-2018_Allgemeine%20Bestimmungen.pdf val akExpressionTurn10 = "AK7-18,AK24,AK30-100/5" val altersklassenTurn10 = Seq( - 6,7,8,9,10,11,12,13,14,15,16,17,18,24,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100 + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 24, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100 ).map(i => ("AK", Seq(), i)) // see https://www.dtb.de/fileadmin/user_upload/dtb.de/Passwesen/Wettkampfordnung_DTB_2021.pdf val akDTBExpression = "AK6,AK18,AK22,AK25" val altersklassenDTB = Seq( - 6,18,22,25 + 6, 18, 22, 25 ).map(i => ("AK", Seq(), i)) // see https://www.dtb.de/fileadmin/user_upload/dtb.de/TURNEN/Standards/PDFs/Rahmentrainingskonzeption-GTm_inklAnlagen_19.11.2020.pdf val akDTBPflichtExpression = "AK8-9,AK11-19/2" val altersklassenDTBPflicht = Seq( - 7,8,9,11,13,15,17,19 + 7, 8, 9, 11, 13, 15, 17, 19 ).map(i => ("AK", Seq(), i)) val akDTBKuerExpression = "AK13-19/2" val altersklassenDTBKuer = Seq( - 12,13,15,17,19 + 12, 13, 15, 17, 19 ).map(i => ("AK", Seq(), i)) val predefinedAKs = Map( @@ -513,6 +634,7 @@ package object domain { , ("DTB Kür" -> akDTBKuerExpression) , ("Individuell" -> "") ) + def apply(altersgrenzen: Seq[(String, Seq[String], Int)]): Seq[Altersklasse] = { if (altersgrenzen.isEmpty) { Seq.empty @@ -548,7 +670,7 @@ package object domain { val intpattern = "([\\D\\s]*)([0-9]+)".r val qualifierPattern = "(.*)\\(([\\D\\s]+)\\)".r - def bez(b: String): (String,Seq[String]) = if(b.nonEmpty) { + def bez(b: String): (String, Seq[String]) = if (b.nonEmpty) { b match { case qualifierPattern(bezeichnung, qualifiers) => (bezeichnung, qualifiers.split("\\+").toSeq) case bezeichnung: String => (bezeichnung, Seq()) @@ -556,13 +678,13 @@ package object domain { } else ("", Seq()) klassenDef.split(",") - .flatMap{ + .flatMap { case rangeStepPattern(bezeichnung, von, bis, stepsize) => Range.inclusive(von, bis, stepsize).map(i => (bez(bezeichnung), i)) case rangepattern(bezeichnung, von, bis) => (str2Int(von) to str2Int(bis)).map(i => (bez(bezeichnung), i)) case intpattern(bezeichnung, von) => Seq((bez(bezeichnung), str2Int(von))) case _ => Seq.empty }.toList - .foldLeft(Seq[(String, Seq[String], Int)]()){(acc, item) => + .foldLeft(Seq[(String, Seq[String], Int)]()) { (acc, item) => if (item._1._1.nonEmpty) { acc :+ (item._1._1, item._1._2, item._2) } else if (acc.nonEmpty) { @@ -573,6 +695,7 @@ package object domain { } .sortBy(item => (item._1, item._3)) } + def apply(klassenDef: String, fallbackBezeichnung: String = "Altersklasse"): Seq[Altersklasse] = { apply(parseGrenzen(klassenDef, fallbackBezeichnung)) } @@ -581,15 +704,19 @@ package object domain { case class Altersklasse(bezeichnung: String, alterVon: Int, alterBis: Int, qualifiers: Seq[String]) extends DataObject { val geschlechtQualifier = qualifiers.filter(q => Seq("M", "W").contains(q)) val programmQualifier = qualifiers.filter(q => !Seq("M", "W").contains(q)) + def matchesAlter(alter: Int): Boolean = ((alterVon == 0 || alter >= alterVon) && (alterBis == 0 || alter <= alterBis)) + def matchesGeschlecht(geschlecht: String): Boolean = { geschlechtQualifier.isEmpty || geschlechtQualifier.contains(geschlecht) } + def matchesProgramm(programm: ProgrammView): Boolean = { programmQualifier.isEmpty || programm.programPath.exists(p => programmQualifier.contains(p.name)) } + override def easyprint: String = { val q = if (qualifiers.nonEmpty) qualifiers.mkString("(", ",", ")") else "" if (alterVon > 0 && alterBis > 0) @@ -601,6 +728,7 @@ package object domain { else s"""$bezeichnung$q bis $alterBis""" } + def easyprintShort: String = { if (alterVon > 0 && alterBis > 0) if (alterVon == alterBis) @@ -624,13 +752,18 @@ package object domain { case class Disziplin(id: Long, name: String) extends DataObject { override def easyprint = name + def equalsOrPause(other: Disziplin) = math.abs(id) == math.abs(other.id) + def isPause: Boolean = id < 0 def asPause: Disziplin = Disziplin(id * -1, s"${name} Pause") + def harmless: Disziplin = Disziplin(math.abs(id), name) + def asNonPause: Disziplin = Disziplin(math.abs(id), name.replace(" Pause", "")) - def normalizedOrdinal(dzl: List[Disziplin]) = dzl.indexOf(asNonPause)+1 + + def normalizedOrdinal(dzl: List[Disziplin]) = dzl.indexOf(asNonPause) + 1 } trait Programm extends DataObject { @@ -658,20 +791,20 @@ package object domain { *
    * Krits        +===========================================+=========================================================
    * aggregate ->|0                                          |1
-   *              +-------------------------------------------+---------------------------------------------------------
+   * +-------------------------------------------+---------------------------------------------------------
    * riegenmode->|1                   |2  / 3(+verein)       |1                     |2  / 3(+verein)
    * Acts         +===========================================+=========================================================
    * Einteilung->| Sex,Pgm,Verein     | Sex,Pgm,Jg(,Verein)  | Sex,Pgm,Verein       | Pgm,Sex,Jg(,Verein)
-   *             +--------------------+----------------------+----------------------+-----------------------------------
+   * +--------------------+----------------------+----------------------+-----------------------------------
    * Teilnahme   | 1/WK               | 1/WK                 | <<=PgmCnt(Jg)/WK      | 1/Pgm
-   *             +-------------------------------------------+----------------------------------------------------------
+   * +-------------------------------------------+----------------------------------------------------------
    * Registration| 1/WK               | 1/WK, Pgm/(Jg)       | mind. 1, max 1/Pgm   | 1/WK aut. Tn 1/Pgm
-   *             +-------------------------------------------+----------------------------------------------------------
+   * +-------------------------------------------+----------------------------------------------------------
    * Beispiele   | GeTu/KuTu/KuTuRi   | Turn10® (BS/OS)      | TG Allgäu (Pfl./Kür) | ATT (Kraft/Bewg)
-   *             +-------------------------------------------+----------------------------------------------------------
+   * +-------------------------------------------+----------------------------------------------------------
    * Rangliste   | Sex/Programm       | Sex/Programm/Jg      | Sex/Programm         | Sex/Programm/Jg
-   *             |                    | Sex/Programm/AK      | Sex/Programm/AK      |
-   *             +===========================================+=========================================================
+   * |                    | Sex/Programm/AK      | Sex/Programm/AK      |
+   * +===========================================+=========================================================
    * 
*/ case class ProgrammRaw(id: Long, name: String, aggregate: Int, parentId: Long, ord: Int, alterVon: Int, alterBis: Int, uuid: String, riegenmode: Int) extends Programm @@ -871,16 +1004,19 @@ package object domain { // } case class WettkampfView(id: Long, uuid: Option[String], datum: java.sql.Date, titel: String, programm: ProgrammView, auszeichnung: Int, auszeichnungendnote: scala.math.BigDecimal, notificationEMail: String, altersklassen: String, jahrgangsklassen: String, punktegleichstandsregel: String, rotation: String, teamrule: String) extends DataObject { override def easyprint = f"$titel am $datum%td.$datum%tm.$datum%tY" + lazy val details: String = s"${programm.name}" + s"${if (teamrule.nonEmpty && !teamrule.equals("Keine Teams")) ", " + teamrule else ""}" + s"${if (altersklassen.nonEmpty) ", Altersklassen" else ""}" + s"${if (jahrgangsklassen.nonEmpty) ", Jahrgangs Altersklassen" else ""}" + "" + def toWettkampf = Wettkampf(id, uuid, datum, titel, programm.id, auszeichnung, auszeichnungendnote, notificationEMail, Option(altersklassen), Option(jahrgangsklassen), Option(punktegleichstandsregel), Option(rotation), Option(teamrule)) } case class WettkampfStats(uuid: String, wkid: Int, titel: String, finishAthletesCnt: Int, finishClubsCnt: Int, finishOnlineAthletesCnt: Int, finishOnlineClubsCnt: Int) extends DataObject { } + case class WettkampfMetaData(uuid: String, wkid: Int, finishAthletesCnt: Int, finishClubsCnt: Int, finishOnlineAthletesCnt: Int, finishOnlineClubsCnt: Int, finishDonationMail: Option[String], finishDonationAsked: Option[BigDecimal], finishDonationApproved: Option[BigDecimal]) extends DataObject { } @@ -934,19 +1070,33 @@ package object domain { } case class Resultat(noteD: scala.math.BigDecimal, noteE: scala.math.BigDecimal, endnote: scala.math.BigDecimal) extends DataObject { - def +(r: Resultat) = Resultat(noteD + r.noteD, noteE + r.noteE, endnote + r.endnote) - def +(r: BigDecimal) = Resultat(noteD + r, noteE + r, endnote + r) + def -(r: Resultat): Resultat = Resultat(noteD - r.noteD, noteE - r.noteE, endnote - r.endnote) - def /(cnt: Int) = Resultat(noteD / cnt, noteE / cnt, endnote / cnt) + def +(r: Resultat): Resultat = Resultat(noteD + r.noteD, noteE + r.noteE, endnote + r.endnote) - def *(cnt: Long) = Resultat(noteD * cnt, noteE * cnt, endnote * cnt) - def *(cnt: BigDecimal) = Resultat(noteD * cnt, noteE * cnt, endnote * cnt) + def -(r: BigDecimal): Resultat = Resultat(noteD - r, noteE - r, endnote - r) - lazy val formattedD = if (noteD > 0) f"${noteD}%4.2f" else "" - lazy val formattedE = if (noteE > 0) f"${noteE}%4.2f" else "" - lazy val formattedEnd = if (endnote > 0) f"${endnote}%6.2f" else "" + def +(r: BigDecimal): Resultat = Resultat(noteD + r, noteE + r, endnote + r) - override def easyprint = f"${formattedD}%6s${formattedE}%6s${formattedEnd}%6s" + def /(cnt: Int): Resultat = Resultat(noteD / cnt, noteE / cnt, endnote / cnt) + + def *(cnt: Long): Resultat = Resultat(noteD * cnt, noteE * cnt, endnote * cnt) + + def *(cnt: BigDecimal): Resultat = Resultat(noteD * cnt, noteE * cnt, endnote * cnt) + + def max(other: Resultat): Resultat = Resultat(noteD.max(other.noteD), noteE.max(other.noteE), endnote.max(other.endnote)) + def min(other: Resultat): Resultat = Resultat(noteD.min(other.noteD), noteE.min(other.noteE), endnote.min(other.endnote)) + def pow(exponent: Int): Resultat = Resultat(noteD.pow(exponent), noteE.pow(exponent), endnote.pow(exponent)) + def sqrt: Resultat = Resultat( + BigDecimal.decimal(Math.sqrt(noteD.toDouble)).setScale(noteD.scale, RoundingMode.HALF_UP), + BigDecimal.decimal(Math.sqrt(noteE.toDouble)).setScale(noteE.scale, RoundingMode.HALF_UP), + BigDecimal.decimal(Math.sqrt(endnote.toDouble)).setScale(endnote.scale, RoundingMode.HALF_UP)) + + lazy val formattedD: String = if (noteD > 0) f"${noteD}%4.2f" else "" + lazy val formattedE: String = if (noteE > 0) f"${noteE}%4.2f" else "" + lazy val formattedEnd: String = if (endnote > 0) f"${endnote}%6.2f" else "" + + override def easyprint: String = f"${formattedD}%6s${formattedE}%6s${formattedEnd}%6s" } case class Wertung(id: Long, athletId: Long, wettkampfdisziplinId: Long, wettkampfId: Long, wettkampfUUID: String, noteD: Option[scala.math.BigDecimal], noteE: Option[scala.math.BigDecimal], endnote: Option[scala.math.BigDecimal], riege: Option[String], riege2: Option[String], team: Option[Int]) extends DataObject { @@ -1015,22 +1165,26 @@ package object domain { trait ResultRow { val athletId: Option[Long] = None val sum: Resultat + lazy val avg = Avg(resultate.map(_.sum).filter(r => r.endnote > 0)) val rang: Resultat val auszeichnung: Boolean val resultate: IndexedSeq[LeafRow] = IndexedSeq() val divider: Int = 1 } + /** * Single Result of a row - * @param title Discipline name + * + * @param title Discipline name * @param sum * @param rang - * @param auszeichnung true, of best score in that discipline + * @param auszeichnung true, if best score in that discipline */ case class LeafRow(title: String, sum: Resultat, rang: Resultat, auszeichnung: Boolean) extends DataRow with ResultRow /** * Row of results per each discipline of one athlet/team + * * @param athlet * @param resultate * @param sum @@ -1050,7 +1204,9 @@ package object domain { sealed trait NotenModus { def getDifficultLabel: String = "D" + def getExecutionLabel: String = "E" + def selectableItems: Option[List[String]] = None def validated(dnote: Double, enote: Double, wettkampfDisziplin: WettkampfdisziplinView): (Double, Double) @@ -1279,6 +1435,7 @@ package object domain { override val caption = s"Athlet/-In korrigieren: Von ${existing.extendedprint} zu ${expected.extendedprint}" def isSexChange: Boolean = existing.geschlecht != expected.geschlecht + def isGebDatChange: Boolean = !existing.gebdat.equals(expected.gebdat) def applyLocalChange: Athlet = existing.copy( diff --git a/src/main/scala/ch/seidel/kutu/renderer/WettkampfOverviewToHtmlRenderer.scala b/src/main/scala/ch/seidel/kutu/renderer/WettkampfOverviewToHtmlRenderer.scala index 178ff990..0e97730f 100644 --- a/src/main/scala/ch/seidel/kutu/renderer/WettkampfOverviewToHtmlRenderer.scala +++ b/src/main/scala/ch/seidel/kutu/renderer/WettkampfOverviewToHtmlRenderer.scala @@ -1,7 +1,7 @@ package ch.seidel.kutu.renderer import ch.seidel.kutu.Config -import ch.seidel.kutu.Config.{homedir, remoteBaseUrl, remoteHostOrigin} +import ch.seidel.kutu.Config.{getRemoteHosts, homedir, remoteBaseUrl, remoteHostOrigin} import ch.seidel.kutu.KuTuApp.enc import ch.seidel.kutu.domain._ import ch.seidel.kutu.renderer.PrintUtil._ @@ -313,6 +313,11 @@ trait WettkampfOverviewToHtmlRenderer { } else { List((("", "", ""), wertungen)) } + // group + // List[(pgm, sex), teams] + val teamGroups = teams.extractTeamsWithDefaultGouping(wertungen) + val allAthletesInTeams = teamGroups.flatMap(_._3.flatMap(_.wertungen.map(_.athlet))).distinct + val groupedTeams = groupedWertungen.toList.flatMap { case (group, wertungen) => teams.extractTeamsWithDefaultGouping(wertungen).groupBy(x => (x._1, x._2)).flatMap { case (grouper, teamgroup) => teamgroup.flatMap(_._3).groupBy(_.rulename).map { @@ -320,7 +325,6 @@ trait WettkampfOverviewToHtmlRenderer { val (pgm, ak, sex) = group val pgmValue = if(grouper._1.contains(pgm)) grouper._1 else pgm + grouper._1 val sexValue = if(grouper._2.contains(sex)) grouper._2 else sex + grouper._2 - //(rulename, pgmValue, ak, sexValue, teams.size, teams.map(team => s"${team.name} (${team.blockrows})").sorted.mkString(", ")) (rulename, pgmValue, ak, sexValue, teams.size, teams.map(team => s"""
  • ${team.name} (${team.blockrows}) |
      @@ -334,26 +338,38 @@ trait WettkampfOverviewToHtmlRenderer { case (rulename, list) => (rulename, list.sortBy(t => s"${t._1}${t._2}${t._3}")) } - + val hasNoExplicitTeamAssignements = !wertungen.exists(_.team > 0) + val unassignedAtletesTeam = Team("Ohne gültige Zuweisung", "", wertungen.filter(w => hasNoExplicitTeamAssignements || w.team > 0).filter(a => !allAthletesInTeams.contains(a.athlet)), Map.empty, Map.empty, Sum) val teamsSections = groupedTeams.keySet.toList.sorted.map { case name => val groupMerges = teamsIndex(name).getGrouperDefs.filter(d => d.exists(_.trim.nonEmpty)) + val mergeRules = if (groupMerges.nonEmpty) { + s""" + |

      Explizite Gruppenzusammenfassungen:

      + |${teamsIndex(name).getGrouperDefs.filter(d => d.exists(_.trim.nonEmpty)).map(d => d.mkString("
    • ", "+", "
    • ")).mkString("
        ", "\n", "

      ")} + |""" + } else "" s"""

      $name

      - |${if (groupMerges.nonEmpty) s""" - |

      Explizite Gruppenzusammenfassungen:

      - |${teamsIndex(name).getGrouperDefs.filter(d => d.exists(_.trim.nonEmpty)).map(d => d.mkString("
    • ", "+", "
    • ")).mkString("
        ", "\n", "

      ")} - |""" else ""} - | + |$mergeRules |
      | | - | - |${ - groupedTeams(name).map { - case (_, pgm: String, ak: String, sex: String, teamssize: Int, teams: String) => - s"" - }.mkString - } + | + | + ${ groupedTeams(name).map { + case (_, pgm: String, ak: String, sex: String, teamssize: Int, teams: String) => + s"" + }.mkString + } + ${if (unassignedAtletesTeam.wertungen.nonEmpty) { + val uat = s"""
      • ${unassignedAtletesTeam.name} (${unassignedAtletesTeam.blockrows}) + |
          + | ${unassignedAtletesTeam.wertungen.map(w => (w.athlet, w.wettkampfdisziplin.programm.name)).distinct.map(a => s"
        • ${a._1.easyprint} (${a._2})
        • ").mkString("")} + |
        + |
      + |""".stripMargin + s"" + } else ""} |
      Prog./Kat.AKGeschlechtAnzahl TeamsTeams
      $pgm$ak$sex$teamssize${teams.replace(",", "
      ")}
      $pgm$ak$sex$teamssize${teams.replace(",", "
      ")}
      Leere (nicht einer Regel entsprechenden) Zuordnungen1$uat
      |""".stripMargin }.mkString("\n") diff --git a/src/main/scala/ch/seidel/kutu/view/DefaultRanglisteTab.scala b/src/main/scala/ch/seidel/kutu/view/DefaultRanglisteTab.scala index 57c96f0e..9ecf2976 100644 --- a/src/main/scala/ch/seidel/kutu/view/DefaultRanglisteTab.scala +++ b/src/main/scala/ch/seidel/kutu/view/DefaultRanglisteTab.scala @@ -88,7 +88,11 @@ abstract class DefaultRanglisteTab(wettkampfmode: BooleanProperty, override val def print(printer: Printer): Unit = { PrintUtil.printWebContent(webView.engine, printer, PageOrientation.Portrait) } - + + def resetFilterPresets(combos: Seq[ComboBox[FilterBy]], scorelistKind: ScoreListKind): Unit = { + + } + def populate(groupers: List[FilterBy]): Seq[ComboBox[FilterBy]] = { val gr1Model = ObservableBuffer.from(groupers) val kindModel = ObservableBuffer.from(Seq[ScoreListKind](Einzelrangliste, Teamrangliste, Kombirangliste)) @@ -312,8 +316,11 @@ abstract class DefaultRanglisteTab(wettkampfmode: BooleanProperty, override val refreshRangliste(buildGrouper) } cbKind.onAction = _ => { - if(!restoring) + if(!restoring) { + restoring = true + resetFilterPresets(combs, cbKind.value.value) refreshRangliste(buildGrouper) + } } val btnPrint = PrintUtil.btnPrintFuture(text.value, getSaveAsFilenameDefault, true, diff --git a/src/main/scala/ch/seidel/kutu/view/RanglisteTab.scala b/src/main/scala/ch/seidel/kutu/view/RanglisteTab.scala index 7690f764..e422d2b4 100644 --- a/src/main/scala/ch/seidel/kutu/view/RanglisteTab.scala +++ b/src/main/scala/ch/seidel/kutu/view/RanglisteTab.scala @@ -6,14 +6,14 @@ import ch.seidel.kutu.Config._ import ch.seidel.kutu.ConnectionStates import ch.seidel.kutu.KuTuApp.handleAction import ch.seidel.kutu.data._ -import ch.seidel.kutu.domain.{Altersklasse, Durchgang, KutuService, TeamRegel, WertungView, WettkampfView, encodeFileName, isNumeric} +import ch.seidel.kutu.domain.{Altersklasse, Durchgang, KutuService, TeamRegel, WertungView, WettkampfView, encodeFileName} import ch.seidel.kutu.renderer.PrintUtil.FilenameDefault import scalafx.Includes.when import scalafx.beans.binding.Bindings import scalafx.beans.property.BooleanProperty import scalafx.event.ActionEvent import scalafx.scene.Node -import scalafx.scene.control.{Button, Label, TextField} +import scalafx.scene.control.{Button, ComboBox, Label, TextField} import scalafx.scene.layout.{BorderPane, Priority, VBox} import scala.concurrent.Await @@ -221,27 +221,38 @@ class RanglisteTab(wettkampfmode: BooleanProperty, wettkampf: WettkampfView, ove btnPublikationFreigeben) } + override def resetFilterPresets(combos: Seq[ComboBox[FilterBy]], scoreListKind: ScoreListKind): Unit = { + val team = groupers.find(p => p.isInstanceOf[ByTeamRule] && p.groupname.startsWith("Wettkampf")) + scoreListKind match { + case Teamrangliste if team.nonEmpty => + combos(1).selectionModel.value.select(team.get) + combos(2).selectionModel.value.clearSelection() + combos(3).selectionModel.value.clearSelection() + + case _ => + val akg = groupers.find(p => p.isInstanceOf[ByAltersklasse] && p.groupname.startsWith("Wettkampf")) + val jakg = groupers.find(p => p.isInstanceOf[ByJahrgangsAltersklasse] && p.groupname.startsWith("Wettkampf")) + if (akg.nonEmpty) { + combos(1).selectionModel.value.select(ByProgramm(programmText)) + combos(2).selectionModel.value.select(akg.get) + combos(3).selectionModel.value.select(ByGeschlecht()) + } else if (jakg.nonEmpty) { + combos(1).selectionModel.value.select(ByProgramm(programmText)) + combos(2).selectionModel.value.select(jakg.get) + combos(3).selectionModel.value.select(ByGeschlecht()) + } else { + combos(1).selectionModel.value.select(ByProgramm(programmText)) + combos(2).selectionModel.value.select(ByGeschlecht()) + } + } + } override def isPopulated = { val combos = populate(groupers) - val akg = groupers.find(p => p.isInstanceOf[ByAltersklasse] && p.groupname.startsWith("Wettkampf")) - val jakg = groupers.find(p => p.isInstanceOf[ByJahrgangsAltersklasse] && p.groupname.startsWith("Wettkampf")) - val team = groupers.find(p => p.isInstanceOf[ByTeamRule] && p.groupname.startsWith("Wettkampf")) - if (akg.nonEmpty) { - combos(1).selectionModel.value.select(ByProgramm(programmText)) - combos(2).selectionModel.value.select(akg.get) - combos(3).selectionModel.value.select(ByGeschlecht()) - } else if (jakg.nonEmpty) { - combos(1).selectionModel.value.select(ByProgramm(programmText)) - combos(2).selectionModel.value.select(jakg.get) - combos(3).selectionModel.value.select(ByGeschlecht()) - } else if (team.nonEmpty) { - combos(1).selectionModel.value.select(team.get) - } else { - combos(1).selectionModel.value.select(ByProgramm(programmText)) - combos(2).selectionModel.value.select(ByGeschlecht()) - } + val team = groupers.find(p => p.isInstanceOf[ByTeamRule] && p.groupname.startsWith("Wettkampf")) + val kind: ScoreListKind = if (getData.exists(_.team > 0) || team.nonEmpty) Teamrangliste else Einzelrangliste + resetFilterPresets(combos, kind) true } diff --git a/src/test/scala/ch/seidel/kutu/domain/PackageSpec.scala b/src/test/scala/ch/seidel/kutu/domain/PackageSpec.scala index 86a4e572..94ed9de1 100644 --- a/src/test/scala/ch/seidel/kutu/domain/PackageSpec.scala +++ b/src/test/scala/ch/seidel/kutu/domain/PackageSpec.scala @@ -3,6 +3,7 @@ package ch.seidel.kutu.domain import ch.seidel.kutu.base.KuTuBaseSpec import java.time.LocalDate +import scala.math.BigDecimal.RoundingMode class PackageSpec extends KuTuBaseSpec { "GeTuWettkampf" should { @@ -118,4 +119,115 @@ class PackageSpec extends KuTuBaseSpec { assert(ar.matchesAthlet().==(true)) } } + "TeamAggreateFun avg" in { + val results1 = List( + Resultat(0, 7.00, 0.08), + Resultat(1, 8.00, 0.12), + Resultat(2, 8.50, 0.06), + Resultat(3, 9.50, 0.23) + ) + val results2 = List( + Resultat(1, 8.00, 0.10), + Resultat(1, 8.20, 0.12), + Resultat(2, 8.50, 0.15), + Resultat(2, 9.10, 0.20) + ) + assert(TeamAggreateFun("avg/")(results1).endnote.<(TeamAggreateFun("avg/")(results2).endnote)) + assert(TeamAggreateFun("avg/")(results1).==(Resultat(1.5, 8.25, 0.1225))) + assert(TeamAggreateFun("avg/")(results2).==(Resultat(1.5, 8.45, 0.1425))) + } + "TeamAggreateFun median even" in { + val results1 = List( + Resultat(0, 7.30, 0.06), + Resultat(1, 8.00, 0.08), + Resultat(2, 8.50, 0.12), + Resultat(3, 9.50, 0.23) + ) + assert(TeamAggreateFun("median/")(results1).==(Resultat(1.5, 8.25, 0.10))) + } + "TeamAggreateFun median odd" in { + val results1 = List( + Resultat(0, 7.00, 0.02), + Resultat(0, 7.30, 0.06), + Resultat(1, 8.00, 0.08), + Resultat(2, 8.50, 0.12), + Resultat(3, 9.50, 0.23) + ) + assert(TeamAggreateFun("median/")(results1).==(Resultat(1, 8.00, 0.08))) + } + "TeamAggreateFun min" in { + val results1 = List( + Resultat(0, 7.00, 0.08), + Resultat(1, 8.00, 0.12), + Resultat(2, 8.50, 0.06), + Resultat(3, 9.50, 0.23) + ) + val results2 = List( + Resultat(1, 8.00, 0.10), + Resultat(1, 8.20, 0.12), + Resultat(2, 8.50, 0.15), + Resultat(2, 9.10, 0.20) + ) + assert(TeamAggreateFun("min/")(results1).endnote.<(TeamAggreateFun("min/")(results2).endnote)) + assert(TeamAggreateFun("min/")(results1).==(Resultat(0, 7.00, 0.06))) + assert(TeamAggreateFun("min/")(results2).==(Resultat(1, 8.00, 0.10))) + } + "TeamAggreateFun max" in { + val results1 = List( + Resultat(0, 7.00, 0.08), + Resultat(1, 8.00, 0.12), + Resultat(2, 8.50, 0.06), + Resultat(3, 9.50, 0.23) + ) + val results2 = List( + Resultat(1, 8.00, 0.10), + Resultat(1, 8.20, 0.12), + Resultat(2, 8.50, 0.15), + Resultat(2, 9.10, 0.20) + ) + assert(TeamAggreateFun("max/")(results1).endnote.>(TeamAggreateFun("max/")(results2).endnote)) + assert(TeamAggreateFun("max/")(results1).==(Resultat(3, 9.50, 0.23))) + assert(TeamAggreateFun("max/")(results2).==(Resultat(2, 9.10, 0.20))) + } + "TeamAggreateFun devmin" in { + val results1 = List( + Resultat(0, 7.00, 0.08), + Resultat(1, 8.00, 0.12), + Resultat(2, 8.50, 0.06), + Resultat(3, 9.50, 0.23) + ) + val results2 = List( + Resultat(1, 8.00, 0.10), + Resultat(1, 8.20, 0.12), + Resultat(2, 8.50, 0.15), + Resultat(2, 9.10, 0.20) + ) + assert(TeamAggreateFun("devmin/")(results1).endnote.>(TeamAggreateFun("devmin/")(results2).endnote)) + assert(TeamAggreateFun("devmin/")(results1).==(Resultat(1.12, 0.9014, 0.06571720))) + assert(TeamAggreateFun("devmin/")(results2).==(Resultat(0.50, 0.4153, 0.03766630))) + } + "TeamAggreateFun devmin2" in { + val results1 = List( + Resultat(0, 7.00, 0.10), + Resultat(1, 8.00, 0.22), + Resultat(2, 8.50, 0.21), + Resultat(3, 9.50, 0.07) + ) + val results2 = List( + Resultat(1, 8.00, 0.47), + Resultat(1, 8.25, 0.42), + Resultat(2, 8.10, 0.31), + Resultat(2, 7.90, 0.26), + Resultat(2, 7.80, 0.76), + Resultat(2, 8.30, 0.90), + Resultat(1, 8.10, 0.47), + Resultat(1, 8.60, 0.42), + Resultat(2, 8.45, 0.31), + Resultat(2, 8.10, 0.26), + Resultat(2, 8.10, 0.76), + Resultat(2, 8.25, 0.90) + ) + assert(TeamAggreateFun("devmin/")(results1).==(Resultat(1.12, 0.9014, 0.06595))) + assert(TeamAggreateFun("devmin/")(results2).noteE.setScale(2, RoundingMode.HALF_DOWN).==(Resultat(0, 0.21, 0).noteE)) + } } \ No newline at end of file diff --git a/src/test/scala/ch/seidel/kutu/domain/TeamRegelTest.scala b/src/test/scala/ch/seidel/kutu/domain/TeamRegelTest.scala index 213c7a38..fcca2ab3 100644 --- a/src/test/scala/ch/seidel/kutu/domain/TeamRegelTest.scala +++ b/src/test/scala/ch/seidel/kutu/domain/TeamRegelTest.scala @@ -51,4 +51,9 @@ class TeamRegelTest extends AnyWordSpec with Matchers { assert( regel.toFormel == "VereinGerät[K5+K6+K7/KH+KD](3/*)" ) } + "VereinGerät(avg/2/*)" in { + val regel = TeamRegel("VereinGerät[K5+K6+K7/KH+KD](avg/2/*)") + assert( regel.teamsAllowed == true ) + assert( regel.toFormel == "VereinGerät[K5+K6+K7/KH+KD](avg/2/*)" ) + } } diff --git a/src/test/scala/ch/seidel/kutu/load/competition/SimulationBottmingenD1.scala b/src/test/scala/ch/seidel/kutu/load/competition/SimulationBottmingenD1.scala index b3263cf2..f1329cee 100644 --- a/src/test/scala/ch/seidel/kutu/load/competition/SimulationBottmingenD1.scala +++ b/src/test/scala/ch/seidel/kutu/load/competition/SimulationBottmingenD1.scala @@ -39,17 +39,51 @@ class SimulationBottmingenD1 extends Simulation { var durchgangListIdx = Map[String, Int]() var geraetListIdx = Map[String, Int]() + val loadAndSaveDurchgaenge = http("get durchgaenge") .get(s"/api/durchgang/$competition") .check( jsonPath("$").exists, - jsonPath("$").ofType[Seq[Any]].find.saveAs("durchgaenge")) + jsonPath("$[*]").findAll.saveAs("durchgaenge")) val loadAndSaveGeraete = http("get geraete") .get(s"/api/durchgang/$competition/geraete") .check( jsonPath("$").exists, - jsonPath("$").ofType[Seq[Any]].find.saveAs("geraete")) + jsonPath("$[*]").ofType[Map[String,Any]].findAll.saveAs("geraete")) + + val loadAndSaveSteps = http("get steps") + .get("/api/durchgang/" + competition + "/#{durchgang}/#{geraet}") + .check( + status.is(200), + jsonPath("$").exists, + jsonPath("$[*]").findAll.saveAs("steps")) + + val connectWSUserToDurchgang = ws("openSocketDG") + .wsName("#{sessionDgUser}") + .connect(s"/api/durchgang/$competition/#{durchgang}/ws?clientid=#{sessionUserId}") + .onConnected( + exec(ws("sendMessage").wsName("#{sessionDgUser}") + .sendText("keepAlive") + .await(5 seconds)(ws.checkTextMessage("check1") + .check(regex("Connection established(.*)").saveAs("wsgreetingmessage")) + .silent) + ) + ) + val closeWSUserFromDurchgang = ws("closeConnectionDG").wsName("#{sessionDgUser}").close + + val connectWSUserToAll = ws("openSocketAll") + .wsName("#{sessionDgUser}-all") + .connect(s"/api/durchgang/$competition/all/ws?clientid=#{sessionUserId}") + .onConnected( + exec(ws("sendMessage").wsName("#{sessionDgUser}-all") + .sendText("keepAlive") + .await(5 seconds)(ws.checkTextMessage("check1") + .check(regex("Connection established(.*)").saveAs("wsgreetingmessage")) + .silent) + ) + ) + val closeWSUserFromAll = ws("closeConnectionAll").wsName("#{sessionDgUser}-all").close def chooseDurchgang(session: Session) = { val list = session("durchgaenge").as[Vector[Any]] @@ -62,48 +96,14 @@ class SimulationBottmingenD1 extends Simulation { } def chooseGeraet(session: Session) = { - val list = session("geraete").as[Vector[Map[String, Int]]].toList + val list = session("geraete").as[Vector[Map[String, Any]]].toList val listIdx = geraetListIdx.getOrElse(session("durchgang").as[String], 0) - val randomEntry = list(listIdx)("id") + val randomEntry: Int = list(listIdx)("id").asInstanceOf[Int] geraetListIdx = geraetListIdx.updated(session("durchgang").as[String], if (listIdx < list.size - 1) listIdx + 1 else 0) println(s"random choosed geraet: $randomEntry") session.set("geraet", randomEntry.toString) } - val connectWSUserToDurchgang = ws("openSocketDG") - .wsName("${sessionDgUser}") - .connect("/api/durchgang/" + competition + "/${durchgang}/ws?clientid=${sessionUserId}") - .onConnected( - exec(ws("sendMessage").wsName("${sessionDgUser}") - .sendText("keepAlive") - .await(5 seconds)(ws.checkTextMessage("check1") - .check(regex("Connection established(.*)").saveAs("wsgreetingmessage")) - .silent) - ) - ) - val connectWSUserToAll = ws("openSocketAll") - .wsName("${sessionDgUser}-all") - .connect("/api/durchgang/" + competition + "/all/ws?clientid=${sessionUserId}") - .onConnected( - exec(ws("sendMessage").wsName("${sessionDgUser}-all") - .sendText("keepAlive") - .await(5 seconds)(ws.checkTextMessage("check1") - .check(regex("Connection established(.*)").saveAs("wsgreetingmessage")) - .silent) - ) - ) - - val closeWSUserFromDurchgang = ws("closeConnectionDG").wsName("${sessionDgUser}").close - val closeWSUserFromAll = ws("closeConnectionAll").wsName("${sessionDgUser}-all").close - - val getSteps = { - exec(http("get steps") - .get("/api/durchgang/" + competition + "/${durchgang}/${geraet}") - .check( - jsonPath("$").exists, - jsonPath("$").ofType[Seq[Any]].find.saveAs("steps"))) - } - def chooseDurchgangWSConnection(session: Session) = { val dg = session("durchgang").as[String] val sessionDgUser = s"${dg}-${session.userId}" @@ -122,13 +122,14 @@ class SimulationBottmingenD1 extends Simulation { val diveToWertungen = commonDGInitializer .exec(connectWSUserToAll) - .exec(getSteps) - .foreach("${steps}", "step") { + .exec(loadAndSaveSteps) + .foreach("#{steps}", "step") { exec(http("get Wertungen") - .get(s"/api/durchgang/$competition/${"${durchgang}"}/${"${geraet}"}/${"${step}"}") + .get(s"/api/durchgang/$competition/#{durchgang}/#{geraet}/#{step}") .check( + status.is(200), jsonPath("$").exists, - jsonPath("$").ofType[Seq[Any]].find)) + jsonPath("$[*]").count.gte(1))) //.pause(5 minutes, 10 minutes) .rendezVous(10) } @@ -138,32 +139,38 @@ class SimulationBottmingenD1 extends Simulation { val collectWertungen = commonDGInitializer .exec(http(s"start durchgang") .post(s"/api/competition/$competition/start") - .body(StringBody(s"""{"type":"StartDurchgangStation","wettkampfUUID":"$competition","durchgang":"${"${durchgangOriginal}"}"}"""))) + .body(StringBody(s"""{"type":"StartDurchgangStation","wettkampfUUID":"$competition","durchgang":"#{durchgangOriginal}"}""")) + .check( + status.is(200) + )) .exec(connectWSUserToDurchgang) - .exec(getSteps) - .foreach("${steps}", "step") { + .exec(loadAndSaveSteps) + .foreach("#{steps}", "step") { exec(http("get Wertungen") - .get(s"/api/durchgang/$competition/${"${durchgang}"}/${"${geraet}"}/${"${step}"}") + .get(s"/api/durchgang/$competition/#{durchgang}/#{geraet}/#{step}") .check( + status.is(200), jsonPath("$").exists, jsonPath("$").ofType[Seq[Any]].find.saveAs("wertungen"))) .pause(1 minutes, 3 minutes) - .foreach("${wertungen}", "wertung") { + .foreach("#{wertungen}", "w") { exec(http("save wertung") - .put(s"/api/durchgang/$competition/${"${durchgang}"}/${"${geraet}"}/${"${step}"}") - .body(StringBody("${wertung.wertung.jsonStringify()}")) + .put(s"/api/durchgang/$competition/#{durchgang}/#{geraet}/#{step}") + .body(StringBody("#{w.wertung.jsonStringify()}")) .check(status.is(200)) ) .pause(5 seconds, 20 seconds) // .exec(http("finish durchgangstation") - // .post(s"/api/durchgang/$competition/${"${durchgang}"}/finish") - // .body(StringBody(s"""{"type":"FinishDurchgangStation","wettkampfUUID":"$competition","durchgang:"${"${durchgangOriginal}"}","geraet":${"${geraet}"},"step":${"${step}"}}"""))) + // .post(s"/api/durchgang/$competition/#{durchgang}/finish") + // .body(StringBody(s"""{"type":"FinishDurchgangStation","wettkampfUUID":"$competition","durchgang:"${"${durchgangOriginal}"}","geraet":#{geraet},"step":#{stept}}"""))) } .rendezVous(12) .exec(http("finish step") .post(s"/api/competition/$competition/finishedStep") .body(StringBody(s"""{"type":"FinishDurchgangStep","wettkampfUUID":"$competition"}""")) - .silent + .silent.check( + status.is(200) + ) ) } .pause(20 seconds, 30 seconds) @@ -178,16 +185,26 @@ class SimulationBottmingenD1 extends Simulation { http("get font roboto-regular").get("/assets/fonts/roboto-regular.woff2"), http("get font roboto-medium").get("/assets/fonts/roboto-medium.woff2"), http("get font roboto-bold").get("/assets/fonts/roboto-bold.woff2"), - http("get competitions").get("/api/competition"), + http("get competitions").get("/api/competition").check( + status.is(200) + ), http("check jwt-token expired") .options("/api/isTokenExpired"))) - .exec(http("startlist").get(s"/api/report/$competition/startlist")) + .exec(http("startlist").get(s"/api/report/$competition/startlist").check( + status.is(200) + )) .exec(BrowseResults.loadAndSaveDurchgaenge) - .exec(http("startlist").get(s"/api/report/$competition/startlist")) + .exec(http("startlist").get(s"/api/report/$competition/startlist").check( + status.is(200) + )) .exec(BrowseResults.loadAndSaveGeraete) - .exec(http("startlist").get(s"/api/report/$competition/startlist")) + .exec(http("startlist").get(s"/api/report/$competition/startlist").check( + status.is(200) + )) .exec(BrowseResults.diveToWertungen) - .exec(http("startlist").get(s"/api/report/$competition/startlist")) + .exec(http("startlist").get(s"/api/report/$competition/startlist").check( + status.is(200) + )) .exec(BrowseResults.closeWSUserFromAll)