From 5c58835b04e0f534e7dd80d7433c5935acedf8e7 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Fri, 16 Aug 2024 10:42:14 +0300 Subject: [PATCH 01/60] Development: Update client dependencies --- package-lock.json | 5122 +++++++---------- package.json | 53 +- .../competency-rings.component.scss | 5 +- .../overview/course-management-card.scss | 16 +- .../students/exam-students.component.scss | 10 +- ...de-hint-generation-overview.component.scss | 6 +- ...-exercise-page-with-details.component.scss | 9 +- .../team-students-online-list.component.scss | 8 +- .../grading-system/bonus/bonus.component.scss | 10 +- .../conversation-messages.component.scss | 10 +- .../webapp/app/overview/course-overview.scss | 4 +- .../course-group/course-group.component.scss | 10 +- .../tutor-participation-graph.component.scss | 6 +- .../app/shared/sidebar/sidebar.component.scss | 3 +- 14 files changed, 2160 insertions(+), 3112 deletions(-) diff --git a/package-lock.json b/package-lock.json index 499b23182e65..4e2059590f91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,18 +10,18 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@angular/animations": "18.1.4", - "@angular/cdk": "18.1.4", - "@angular/common": "18.1.4", - "@angular/compiler": "18.1.4", - "@angular/core": "18.1.4", - "@angular/forms": "18.1.4", - "@angular/localize": "18.1.4", - "@angular/material": "18.1.4", - "@angular/platform-browser": "18.1.4", - "@angular/platform-browser-dynamic": "18.1.4", - "@angular/router": "18.1.4", - "@angular/service-worker": "18.1.4", + "@angular/animations": "18.2.0", + "@angular/cdk": "18.2.0", + "@angular/common": "18.2.0", + "@angular/compiler": "18.2.0", + "@angular/core": "18.2.0", + "@angular/forms": "18.2.0", + "@angular/localize": "18.2.0", + "@angular/material": "18.2.0", + "@angular/platform-browser": "18.2.0", + "@angular/platform-browser-dynamic": "18.2.0", + "@angular/router": "18.2.0", + "@angular/service-worker": "18.2.0", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.1.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -34,7 +34,7 @@ "@ng-bootstrap/ng-bootstrap": "17.0.0", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", - "@sentry/angular": "8.25.0", + "@sentry/angular": "8.26.0", "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", @@ -61,7 +61,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.0", + "posthog-js": "1.155.4", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -79,22 +79,22 @@ }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.1.4", - "@angular-eslint/builder": "18.2.0", - "@angular-eslint/eslint-plugin": "18.2.0", - "@angular-eslint/eslint-plugin-template": "18.2.0", - "@angular-eslint/schematics": "18.2.0", - "@angular-eslint/template-parser": "18.2.0", - "@angular/cli": "18.1.4", - "@angular/compiler-cli": "18.1.4", - "@angular/language-service": "18.1.4", - "@sentry/types": "8.25.0", + "@angular-devkit/build-angular": "18.2.0", + "@angular-eslint/builder": "18.3.0", + "@angular-eslint/eslint-plugin": "18.3.0", + "@angular-eslint/eslint-plugin-template": "18.3.0", + "@angular-eslint/schematics": "18.3.0", + "@angular-eslint/template-parser": "18.3.0", + "@angular/cli": "18.2.0", + "@angular/compiler-cli": "18.2.0", + "@angular/language-service": "18.2.0", + "@sentry/types": "8.26.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.2.0", + "@types/node": "22.3.0", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", @@ -117,7 +117,7 @@ "jest-fail-on-console": "3.3.0", "jest-junit": "16.0.0", "jest-preset-angular": "14.2.2", - "lint-staged": "15.2.8", + "lint-staged": "15.2.9", "ng-mocks": "14.13.0", "prettier": "3.3.3", "sass": "1.77.8", @@ -211,13 +211,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1801.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.4.tgz", - "integrity": "sha512-Ch1ZwRh1N/vcCKHm4ErLcgZly3tlwdLUDGBaAIlhE3YFGq543Swv6a5IcDw0veD6iGFceJAmbrp+z5hmzI8p5A==", + "version": "0.1802.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.0.tgz", + "integrity": "sha512-s1atTSL98XLUUxfWEQAnhFaOFIJZDLWjSqec+Sb+f4iZFj+hOFejzJxPVnHMIJudOzn0Lqjk3t987KG/zNEGdg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.4", + "@angular-devkit/core": "18.2.0", "rxjs": "7.8.1" }, "engines": { @@ -227,48 +227,48 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.1.4.tgz", - "integrity": "sha512-CCoPT2fFw1DD3j9eSP3GKbp9KfvxQQfY6kV2aec0pqL/c6byz4/ku+rsV4lwE0N/dcaglwhttq4Xf+u+pkEpiw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.0.tgz", + "integrity": "sha512-V0XKT7xt6d6duXqmDAQEQgEJNXuWAekpHEDxafvBT0MTxcEhu0ozQVwI4oAekiKOz+APIcAZyMzvw3Tlzog5cw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.4", - "@angular-devkit/build-webpack": "0.1801.4", - "@angular-devkit/core": "18.1.4", - "@angular/build": "18.1.4", - "@babel/core": "7.24.7", - "@babel/generator": "7.24.7", + "@angular-devkit/architect": "0.1802.0", + "@angular-devkit/build-webpack": "0.1802.0", + "@angular-devkit/core": "18.2.0", + "@angular/build": "18.2.0", + "@babel/core": "7.25.2", + "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", - "@babel/plugin-transform-async-generator-functions": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.25.0", "@babel/plugin-transform-async-to-generator": "7.24.7", "@babel/plugin-transform-runtime": "7.24.7", - "@babel/preset-env": "7.24.7", - "@babel/runtime": "7.24.7", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "18.1.4", + "@babel/preset-env": "7.25.3", + "@babel/runtime": "7.25.0", + "@discoveryjs/json-ext": "0.6.1", + "@ngtools/webpack": "18.2.0", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "autoprefixer": "10.4.19", + "autoprefixer": "10.4.20", "babel-loader": "9.1.3", "browserslist": "^4.21.5", "copy-webpack-plugin": "12.0.2", "critters": "0.0.24", "css-loader": "7.1.2", - "esbuild-wasm": "0.21.5", + "esbuild-wasm": "0.23.0", "fast-glob": "3.3.2", "http-proxy-middleware": "3.0.0", "https-proxy-agent": "7.0.5", - "istanbul-lib-instrument": "6.0.2", + "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", "less": "4.2.0", "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.3.1", - "magic-string": "0.30.10", + "magic-string": "0.30.11", "mini-css-extract-plugin": "2.9.0", "mrmime": "2.0.0", "open": "10.1.0", @@ -276,25 +276,24 @@ "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "postcss": "8.4.38", + "postcss": "8.4.41", "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.77.6", - "sass-loader": "14.2.1", - "semver": "7.6.2", + "sass": "1.77.8", + "sass-loader": "16.0.0", + "semver": "7.6.3", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.29.2", + "terser": "5.31.6", "tree-kill": "1.2.2", "tslib": "2.6.3", - "undici": "6.19.2", - "vite": "5.3.2", + "vite": "5.4.0", "watchpack": "2.4.1", - "webpack": "5.92.1", - "webpack-dev-middleware": "7.2.1", + "webpack": "5.93.0", + "webpack-dev-middleware": "7.3.0", "webpack-dev-server": "5.0.4", - "webpack-merge": "5.10.0", + "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, "engines": { @@ -303,7 +302,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.21.5" + "esbuild": "0.23.0" }, "peerDependencies": { "@angular/compiler-cli": "^18.0.0", @@ -356,32 +355,14 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/sass": { - "version": "1.77.6", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", - "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1801.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1801.4.tgz", - "integrity": "sha512-Srhs/PcnuUaMiO9FLQLi1QiGZqtnG5NTpkufjJuWxolSLGNRmb/h/ZeCYgRnxeH/4jd8GCD31RD78qy+pviiLQ==", + "version": "0.1802.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.0.tgz", + "integrity": "sha512-bU7AxlI/avnlOLrgE195cokrOA1ayT6JjRv8Hxzh1bIOa1jE87HsyjxvQhOLcdEb97zwHqMqbntcgUNBgsegJQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.4", + "@angular-devkit/architect": "0.1802.0", "rxjs": "7.8.1" }, "engines": { @@ -395,13 +376,13 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.4.tgz", - "integrity": "sha512-lKBsvbqW2QFL8terzNuSDSmKBo8//QNRO4qU5mVJ1fFf4xBJanXKoiAMuADhx+/owVIptnYT59IZ8jUAna+Srg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.0.tgz", + "integrity": "sha512-8SOopyUKUMqAq2rj32XkTIfr79Y274k4uglxxRtzHYoWwHlLdG0KrA+wCcsh/FU9PyR4dA+5dcDAApn358ZF+Q==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.16.0", + "ajv": "8.17.1", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", "picomatch": "4.0.2", @@ -423,15 +404,15 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.4.tgz", - "integrity": "sha512-0ekArCeYqJngCKWZ9I+RtNObP/33zGkzWdJOmCB6nj9/ZevALZ6F4RDkHp0TqDYhOt+A2muI29ZK/cILmKA+sA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.0.tgz", + "integrity": "sha512-WWKwz2RKMVI6T25JFwOSSfRLB+anNzabVIRwf85R/YMIo34BUk777f2JU/7cCKlxSpQu39TqIfMQZAyzAD1z0A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.4", + "@angular-devkit/core": "18.2.0", "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", + "magic-string": "0.30.11", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -442,36 +423,32 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.2.0.tgz", - "integrity": "sha512-2NsrYqvVVha2XUUXm1T0XshW0d1TzYU6rXNCTut1t8qS/uinbxNiszKzJN1TuUsXFwpZfITRnEY3cjaqJDlsdA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.0.tgz", + "integrity": "sha512-httEQyqyBw3+0CRtAa7muFxHrauRfkEfk/jmrh5fn2Eiu+I53hAqFPgrwVi1V6AP/kj2zbAiWhd5xM3pMJdoRQ==", "dev": true, "license": "MIT", - "dependencies": { - "@nx/devkit": "^19.0.6", - "nx": "^19.0.6" - }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.2.0.tgz", - "integrity": "sha512-p/YvlvDJscSAbNOOAbT/BRdscEfWpQunUK+KuWM6/PXL07tTVae5dmp8B8A5am7Cxvp+ZVLVLZG4LFYB1TX1cw==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.0.tgz", + "integrity": "sha512-v/59FxUKnMzymVce99gV43huxoqXWMb85aKvzlNvLN+ScDu6ZE4YMiTQNpfapVL2lkxhs0uwB3jH17EYd5TcsA==", "dev": true, "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.2.0.tgz", - "integrity": "sha512-vJ7pstQPqCqkvMrEsjjocvHdPBl/frs0+fqkckog2Sq0QisBEjUPkbImvId6dw7JzxSDSvttdAklakF97CE4VA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.0.tgz", + "integrity": "sha512-Vl7gfPMXxvtHTjYdlzR161aj5xrqW6T57wd8ToQ7Gqzm0qHGfY6kE4SQobUa2LCYckTNSlv+zXe48C4ah/dSjw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.2.0", - "@angular-eslint/utils": "18.2.0" + "@angular-eslint/bundled-angular-compiler": "18.3.0", + "@angular-eslint/utils": "18.3.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", @@ -480,14 +457,14 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.2.0.tgz", - "integrity": "sha512-YHh+AUY9ubLAdmIRXH8vSpv+8EQkGjdX3B9xdj/grnrVzgzu+5W86F/spGp2tEny9l85R3JZNqjaMpW/vwibfw==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.0.tgz", + "integrity": "sha512-ddR/qwYbUeq9IpyVKrPbfZyRBTy6V8uc5I0JcBKttQ4CZ4joXhqsVgWFsI+JAMi8E66uNj1VC7NuKCOjDINv2Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.2.0", - "@angular-eslint/utils": "18.2.0", + "@angular-eslint/bundled-angular-compiler": "18.3.0", + "@angular-eslint/utils": "18.3.0", "aria-query": "5.3.0", "axobject-query": "4.1.0" }, @@ -498,17 +475,15 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-18.2.0.tgz", - "integrity": "sha512-6niXUrwyAmhuFcsRx88cOOVrko0EmsUGjLZ4yso3op/I9ZgI4SfuLCtl9gzJIR4TLBYc4zAuC/TE/rsLP+WCtw==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-18.3.0.tgz", + "integrity": "sha512-rQ4DEWwf3f5n096GAK6JvXD0SRzRJ52WRaIyKg8MMkk6qvUDfZI8seOkcbjDtZoIe6Ds7DfqSfJgNVte75qvPQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/eslint-plugin": "18.2.0", - "@angular-eslint/eslint-plugin-template": "18.2.0", - "@nx/devkit": "^19.0.6", - "ignore": "5.3.1", - "nx": "^19.0.6", + "@angular-eslint/eslint-plugin": "18.3.0", + "@angular-eslint/eslint-plugin-template": "18.3.0", + "ignore": "5.3.2", "semver": "7.6.3", "strip-json-comments": "3.1.1" }, @@ -518,13 +493,13 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.2.0.tgz", - "integrity": "sha512-1jKH2fL8ir1ajcgu/N0xIWVtlpJQmbJBRRe1+WbBoomykcu1KnLwCSue/LuUDQOf3CTmMHxQE0f+58VpafYoyA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.0.tgz", + "integrity": "sha512-1mUquqcnugI4qsoxcYZKZ6WMi6RPelDcJZg2YqGyuaIuhWmi3ZqJZLErSSpjP60+TbYZu7wM8Kchqa1bwJtEaQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.2.0", + "@angular-eslint/bundled-angular-compiler": "18.3.0", "eslint-scope": "^8.0.2" }, "peerDependencies": { @@ -533,13 +508,13 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.2.0.tgz", - "integrity": "sha512-g+b0L4RCZaKYPz4bGRRifo7g5guVJi2kUWymlDYmCkq3NhZng1HQQbNpVF1n5o034zT5lnaC5HENwaKIZ1Y37Q==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.0.tgz", + "integrity": "sha512-sCrkHkpxBJZLuCikdboZoawCfc2UgbJv+T14tu2uQCv+Vwzeadnu04vkeY2vTkA8GeBdBij/G9/N/nvwmwVw3g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.2.0" + "@angular-eslint/bundled-angular-compiler": "18.3.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", @@ -548,9 +523,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.1.4.tgz", - "integrity": "sha512-m0yusB7BI3wrotx9F9rf7YUD5bvhF+lT2fLNF1QCzCU819rtLnDoj0b4/z+D0i5qe7gQjtAJ42e/Hv7eGuq0VQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.0.tgz", + "integrity": "sha512-BFAfqDDjsa0Q91F4s33pFcBG+ydFDurEmwYGG1gmO7UXZJI6ZbRVdULaZHz75M+Bf3hJkzVB05pesvfbK+Fg/g==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -559,42 +534,40 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.4" + "@angular/core": "18.2.0" } }, "node_modules/@angular/build": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.1.4.tgz", - "integrity": "sha512-jkqccHpGhxUOe0zIHpA1nPdeuPUxnBK7Wvazc2rA+ccI30BPrROkEDbrHP8yD8JeviUCFwwLE+hM+rRg+NneVw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.0.tgz", + "integrity": "sha512-LvNJ2VOEVy3N1tGzt+xnKyweRBuUE1NsnuEEWAb9Y+V1cyRgj0s7FX2+IQZZQhP+W/pXfbsKaByOAbJ5KWV85Q==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.4", - "@babel/core": "7.24.7", + "@angular-devkit/architect": "0.1802.0", + "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-syntax-import-attributes": "7.24.7", - "@inquirer/confirm": "3.1.11", + "@inquirer/confirm": "3.1.22", "@vitejs/plugin-basic-ssl": "1.1.0", - "ansi-colors": "4.1.3", "browserslist": "^4.23.0", "critters": "0.0.24", - "esbuild": "0.21.5", + "esbuild": "0.23.0", "fast-glob": "3.3.2", "https-proxy-agent": "7.0.5", - "lmdb": "3.0.12", - "magic-string": "0.30.10", + "listr2": "8.2.4", + "lmdb": "3.0.13", + "magic-string": "0.30.11", "mrmime": "2.0.0", - "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "rollup": "4.18.0", - "sass": "1.77.6", - "semver": "7.6.2", - "undici": "6.19.2", - "vite": "5.3.2", + "rollup": "4.20.0", + "sass": "1.77.8", + "semver": "7.6.3", + "vite": "5.4.0", "watchpack": "2.4.1" }, "engines": { @@ -633,28 +606,10 @@ } } }, - "node_modules/@angular/build/node_modules/sass": { - "version": "1.77.6", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", - "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@angular/cdk": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.1.4.tgz", - "integrity": "sha512-xFOg2wT2iLyJXqgeNRK1uF4Lxn0B1wzBjaEQoOwFm1EHOdu5D4mNOTwfuB3DkH4KWM+mI3Qtxd7vOhOXNwB3Dg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.0.tgz", + "integrity": "sha512-hjuUWNhxU48WB2i1j4NLwnPTaCnucRElfp7DBX5Io0rY5Lwl3HXafvyi7/A1D0Ah+YsJpktKOWPDGv8r7vxymg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -669,27 +624,27 @@ } }, "node_modules/@angular/cli": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.4.tgz", - "integrity": "sha512-ppX4iilA6k+sKD6iRMRYnt2bH9Jpik+hJlndRBCjWo2EmEUQ04CBRKYONh8BLbnmwBxPG+/osUpcFrbkPCjQUw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.0.tgz", + "integrity": "sha512-hA60QIA7Dh8LQxM42wqd7WrhwQjbjB8oIRH5Slgbiv8iocAo76scp1/qyZo2SSzjfkB7jxUiao5L4ckiJ/hvZg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.4", - "@angular-devkit/core": "18.1.4", - "@angular-devkit/schematics": "18.1.4", - "@inquirer/prompts": "5.0.7", - "@listr2/prompt-adapter-inquirer": "2.0.13", - "@schematics/angular": "18.1.4", + "@angular-devkit/architect": "0.1802.0", + "@angular-devkit/core": "18.2.0", + "@angular-devkit/schematics": "18.2.0", + "@inquirer/prompts": "5.3.8", + "@listr2/prompt-adapter-inquirer": "2.0.15", + "@schematics/angular": "18.2.0", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", - "listr2": "8.2.3", - "npm-package-arg": "11.0.2", - "npm-pick-manifest": "9.0.1", + "listr2": "8.2.4", + "npm-package-arg": "11.0.3", + "npm-pick-manifest": "9.1.0", "pacote": "18.0.6", "resolve": "1.22.8", - "semver": "7.6.2", + "semver": "7.6.3", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -703,9 +658,9 @@ } }, "node_modules/@angular/common": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.1.4.tgz", - "integrity": "sha512-No4lCrL80WlAGg0DAyuPW+jsfA6EIQ06CFrRgt3R6YFrKbIuU0NKUt+D8IB7UNgTLNYXmurxapNf8jef8rq1wg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.0.tgz", + "integrity": "sha512-DELx/QYNqqjmiM+kE5PoVmyG4gPw5WB1bDDeg3hEuBCK3eS2KosgQH0/MQo3OSBZHOcAMFjfHMGqKgxndmYixQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -714,14 +669,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.4", + "@angular/core": "18.2.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.1.4.tgz", - "integrity": "sha512-Xdvm9trEmrWZaxCk3a7bt5kN/jdXBPukVsibFpu5lKl9ZL7j2sn4JUd7j/dVNRUIVsPahQMATAOgl8xdUJzh4Q==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.0.tgz", + "integrity": "sha512-RmGwQ7jRzotUKKMk0CwxTcIXFr5mRxSbJf9o5S3ujuIOo1lYop8SQZvjq67a5BuoYyD+1pX6iMmxZqlbKoihBQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -730,7 +685,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.4" + "@angular/core": "18.2.0" }, "peerDependenciesMeta": { "@angular/core": { @@ -739,12 +694,12 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.1.4.tgz", - "integrity": "sha512-wOOLzxPLsDYsD+f6Bqr31ol8K7I4cm4k5uuaQl+wkLBpX9AD1rMi/7CPJrXAWBdgOW67uPzAdLBsK+axKfg91w==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.0.tgz", + "integrity": "sha512-pPBFjMqNTNettrleLtEc6a/ysOZjG3F0Z5lyKYePcyNQmn2rpa9XmD2y6PhmzTmIhxeXrogWA84Xgg/vK5wBNw==", "license": "MIT", "dependencies": { - "@babel/core": "7.24.9", + "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -762,65 +717,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.4", + "@angular/compiler": "18.2.0", "typescript": ">=5.4 <5.6" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@angular/core": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.1.4.tgz", - "integrity": "sha512-+N3oWYFubT3GdCkBfD/CmH4DGjr/fGFQZChWbph2ZuPpK7JYNgfyvXS4SjLtdL4WTjjBevBTgR70GyLH/5EbKA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.0.tgz", + "integrity": "sha512-7+4wXfeAk1TnG3MGho2gpBI5XHxeSRWzLK2rC5qyyRbmMV+GrIgf1HqFjQ4S02rydkQvGpjqQHtO1PYJnyn4bg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -830,13 +734,13 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.14.10" } }, "node_modules/@angular/forms": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.1.4.tgz", - "integrity": "sha512-PYaQ7/2toAwgJWIznVWgJAd3l8mjAreilGOVIMbBIaotL/EHRQjhlikitJEFDGXeVUarY/rm3IlLWBYnLyliyg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.0.tgz", + "integrity": "sha512-G+4BjNCUo4cRwg9NwisGLbtG/1AbIJNOO3RUejPJJbCcAkYMSzmDWSQ+LQEGW4vC/1xaDKO8AT71DI/I09bOxA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -845,16 +749,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.4", - "@angular/core": "18.1.4", - "@angular/platform-browser": "18.1.4", + "@angular/common": "18.2.0", + "@angular/core": "18.2.0", + "@angular/platform-browser": "18.2.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.1.4.tgz", - "integrity": "sha512-nvO6lG/vMWRXUj+nY2HyvhOSlSYqBx1ER2rk5MezzYo3I0qgiNuV9YfgTyXLWywDAvc9jcTrIyi4nxBm6a0xvQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.0.tgz", + "integrity": "sha512-brl5061YqfNnT7yZNMWmsgv6ve6p9+kfhX6mZWOGICcY2SYVtCNVHdqzwWTTwY7MvTVfycHxiAf9PEmc5lD4/g==", "dev": true, "license": "MIT", "engines": { @@ -862,12 +766,12 @@ } }, "node_modules/@angular/localize": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.1.4.tgz", - "integrity": "sha512-GqrVYc3PwYFd9nDbOV0nL2ZhsLfb1LOZLnpsGqTBJT6zfmbqTUnwQWjHmj6SoGzTQl9r9OAvawaMrICzB6Rrfw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.2.0.tgz", + "integrity": "sha512-ul8yGmimiHkhUU87isDCst0790jTBHP1zPBMI2q7QHv7iDzSN5brV8zUMcRypxhh4mQOCnq2LtP84o5ybn4Sig==", "license": "MIT", "dependencies": { - "@babel/core": "7.24.9", + "@babel/core": "7.25.2", "@types/babel__core": "7.20.5", "fast-glob": "3.3.2", "yargs": "^17.2.1" @@ -881,72 +785,21 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.4", - "@angular/compiler-cli": "18.1.4" - } - }, - "node_modules/@angular/localize/node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/localize/node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" + "@angular/compiler": "18.2.0", + "@angular/compiler-cli": "18.2.0" } }, - "node_modules/@angular/localize/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, "node_modules/@angular/material": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.1.4.tgz", - "integrity": "sha512-xmKIVOKZA8yFXrw4PsBvShFSYFQCnuVNGGuJlc8S8xvURh/f9P6hAo1Ua9pSBkOKz2W2dHE+726zOqL+o4kNxg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.0.tgz", + "integrity": "sha512-lOXk8pAVP4Mr0/Q6YrNnVYQVTnR8aEG5D9QSEWjs+607gONuh/9n7ERBdzX7xO9D0vYyXq+Vil32zcF41/Q8Cg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.1.4", + "@angular/cdk": "18.2.0", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -955,9 +808,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.1.4.tgz", - "integrity": "sha512-zGx33St0JVYT8EZOaf0s8Twr0RgfU2cqEAc9Wwx9HVJ0pF5y4VnftK3pewwiHWDHkPfiJy0jBKbtrkVUSbgZfg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.0.tgz", + "integrity": "sha512-yhj281TuPz5a8CehwucwIVl29Oqte9KS4X/VQkMV++GpYQE2KKKcoff4FXSdF5RUcUYkK2li4IvawIqPmUSagg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -966,9 +819,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.1.4", - "@angular/common": "18.1.4", - "@angular/core": "18.1.4" + "@angular/animations": "18.2.0", + "@angular/common": "18.2.0", + "@angular/core": "18.2.0" }, "peerDependenciesMeta": { "@angular/animations": { @@ -977,9 +830,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.1.4.tgz", - "integrity": "sha512-ZQQcKXGIriOzILTZxIbmDpGnwuiwfJ0xh2EmmnfC0zh/NB+li6whgplOLEciaHgsUKtDn7kNZFn2vKrx+B/cDQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.0.tgz", + "integrity": "sha512-izfaXKNC/kqOEzJG8eTnFu39VLI3vv3dTKoYOdEKRB7MTI0t0x66oZmABnHcihtkTSvXs/is+7lA5HmH2ZuIEQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -988,16 +841,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.4", - "@angular/compiler": "18.1.4", - "@angular/core": "18.1.4", - "@angular/platform-browser": "18.1.4" + "@angular/common": "18.2.0", + "@angular/compiler": "18.2.0", + "@angular/core": "18.2.0", + "@angular/platform-browser": "18.2.0" } }, "node_modules/@angular/router": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.1.4.tgz", - "integrity": "sha512-982+bnO3uGFYjRFcQDoKmnWvUcZUvFxEpX/I2Yu+WmPJrY7fPJ693mBaWgwVFa0xIBNfjvJjNXdikGBz5UrMsw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.0.tgz", + "integrity": "sha512-6/462hvC3HSwbps8VItECHpkdkiFqRmTKdn1Trik+FjnvdupYrKB6kBsveM3eP+gZD4zyMBMKzBWB9N/xA1clw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1006,16 +859,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.4", - "@angular/core": "18.1.4", - "@angular/platform-browser": "18.1.4", + "@angular/common": "18.2.0", + "@angular/core": "18.2.0", + "@angular/platform-browser": "18.2.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.1.4.tgz", - "integrity": "sha512-7knx0I82ud6IWu2NOEtmtikApm/Ix8YEbXk2/J8YiN7ozGSTjTK5X8cpvFUzfG4MbARH6sxVAPffNJduzW4ZAw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.0.tgz", + "integrity": "sha512-ngcALrgqMuAeIo5dgou6eBzdtgLvmVg5zwmZuTyrnNPZENEaKTj7u5pm9++gl62797sUWlMbL+fa/BOhntGs5A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1027,8 +880,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.4", - "@angular/core": "18.1.4" + "@angular/common": "18.2.0", + "@angular/core": "18.2.0" } }, "node_modules/@babel/code-frame": { @@ -1054,21 +907,21 @@ } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -1090,12 +943,12 @@ "license": "MIT" }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -1203,19 +1056,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", @@ -1461,6 +1301,22 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", @@ -1839,16 +1695,16 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2029,6 +1885,23 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", @@ -2661,20 +2534,21 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -2695,29 +2569,30 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", "@babel/plugin-transform-dynamic-import": "^7.24.7", "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-new-target": "^7.24.7", @@ -2726,7 +2601,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-object-super": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", @@ -2737,7 +2612,7 @@ "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", "@babel/plugin-transform-unicode-escapes": "^7.24.7", "@babel/plugin-transform-unicode-property-regex": "^7.24.7", "@babel/plugin-transform-unicode-regex": "^7.24.7", @@ -2746,7 +2621,7 @@ "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.4", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -2779,9 +2654,9 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -2822,21 +2697,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", @@ -2909,44 +2769,13 @@ } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz", + "integrity": "sha512-boghen8F0Q8D+0/Q1/1r6DUEieUJ8w2a1gIknExMSHBsJFOr2+0KUfHiVYBvucPwl3+RU5PFBK833FjFCh3BhA==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.2.0.tgz", - "integrity": "sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/wasi-threads": "1.0.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", - "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" + "node": ">=14.17.0" } }, "node_modules/@emotion/is-prop-valid": { @@ -2977,9 +2806,9 @@ "license": "MIT" }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", "cpu": [ "ppc64" ], @@ -2990,13 +2819,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", "cpu": [ "arm" ], @@ -3007,13 +2836,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", "cpu": [ "arm64" ], @@ -3024,13 +2853,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", "cpu": [ "x64" ], @@ -3041,13 +2870,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], @@ -3058,13 +2887,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", "cpu": [ "x64" ], @@ -3075,13 +2904,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", "cpu": [ "arm64" ], @@ -3092,13 +2921,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", "cpu": [ "x64" ], @@ -3109,13 +2938,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", "cpu": [ "arm" ], @@ -3126,13 +2955,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", "cpu": [ "arm64" ], @@ -3143,13 +2972,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", "cpu": [ "ia32" ], @@ -3160,13 +2989,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", "cpu": [ "loong64" ], @@ -3177,13 +3006,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", "cpu": [ "mips64el" ], @@ -3194,13 +3023,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", "cpu": [ "ppc64" ], @@ -3211,13 +3040,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ "riscv64" ], @@ -3228,13 +3057,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", "cpu": [ "s390x" ], @@ -3245,13 +3074,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", "cpu": [ "x64" ], @@ -3262,13 +3091,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", "cpu": [ "x64" ], @@ -3279,13 +3108,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", "cpu": [ "x64" ], @@ -3296,13 +3142,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", "cpu": [ "x64" ], @@ -3313,13 +3159,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", "cpu": [ "arm64" ], @@ -3330,13 +3176,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", "cpu": [ "ia32" ], @@ -3347,13 +3193,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "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.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", "cpu": [ "x64" ], @@ -3364,7 +3210,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3673,87 +3519,45 @@ "node": ">=18" } }, - "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@inquirer/confirm": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.11.tgz", - "integrity": "sha512-3wWw10VPxQP279FO4bzWsf8YjIAq7NdwATJ4xS2h1uwsXZu/RmtOVV95rZ7yllS1h/dzu+uLewjMAzNDEj8h2w==", + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^8.2.4", - "@inquirer/type": "^1.3.3" + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/core": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.2.4.tgz", - "integrity": "sha512-7vsXSfxtrrbwMTirfaKwPcjqJy7pzeuF/bP62yo1NQrRJ5HjmMlrhZml/Ljm9ODc1RnbhJlTeSnCkjtFddKjwA==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.3", - "@inquirer/type": "^1.3.3", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.9", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", "cli-width": "^4.1.0", "mute-stream": "^1.0.0", - "picocolors": "^1.0.1", "signal-exit": "^4.1.0", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/core/node_modules/@types/node": { - "version": "20.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", - "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@inquirer/core/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, "node_modules/@inquirer/editor": { "version": "2.1.22", "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.22.tgz", @@ -3769,31 +3573,6 @@ "node": ">=18" } }, - "node_modules/@inquirer/editor/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@inquirer/expand": { "version": "2.1.22", "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.22.tgz", @@ -3809,31 +3588,6 @@ "node": ">=18" } }, - "node_modules/@inquirer/expand/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@inquirer/figures": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", @@ -3858,26 +3612,15 @@ "node": ">=18" } }, - "node_modules/@inquirer/input/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "node_modules/@inquirer/number": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.0.10.tgz", + "integrity": "sha512-kWTxRF8zHjQOn2TJs+XttLioBih6bdc5CcosXIzZsrTY383PXI35DuhIllZKu7CdXFi2rz2BWPN9l0dPsvrQOA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" }, "engines": { "node": ">=18" @@ -3898,46 +3641,23 @@ "node": ">=18" } }, - "node_modules/@inquirer/password/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@inquirer/prompts": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.0.7.tgz", - "integrity": "sha512-GFcigCxJTKCH3aECzMIu4FhgLJWnFvMXzpI4CCSoELWFtkOOU2P+goYA61+OKpGrB8fPE7q6n8zAXBSlZRrHjQ==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.3.8.tgz", + "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^2.3.7", - "@inquirer/confirm": "^3.1.11", - "@inquirer/editor": "^2.1.11", - "@inquirer/expand": "^2.1.11", - "@inquirer/input": "^2.1.11", - "@inquirer/password": "^2.1.11", - "@inquirer/rawlist": "^2.1.11", - "@inquirer/select": "^2.3.7" + "@inquirer/checkbox": "^2.4.7", + "@inquirer/confirm": "^3.1.22", + "@inquirer/editor": "^2.1.22", + "@inquirer/expand": "^2.1.22", + "@inquirer/input": "^2.2.9", + "@inquirer/number": "^1.0.10", + "@inquirer/password": "^2.1.22", + "@inquirer/rawlist": "^2.2.4", + "@inquirer/search": "^1.0.7", + "@inquirer/select": "^2.4.7" }, "engines": { "node": ">=18" @@ -3958,25 +3678,16 @@ "node": ">=18" } }, - "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "node_modules/@inquirer/search": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.0.7.tgz", + "integrity": "sha512-p1wpV+3gd1eST/o5N3yQpYEdFNCzSP0Klrl+5bfD3cTTz8BGG6nf4Z07aBW0xjlKIj1Rp0y3x/X4cZYi6TfcLw==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/core": "^9.0.10", "@inquirer/figures": "^1.0.5", "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -4000,31 +3711,6 @@ "node": ">=18" } }, - "node_modules/@inquirer/select/node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@inquirer/type": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", @@ -5074,13 +4760,13 @@ "license": "MIT" }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.13.tgz", - "integrity": "sha512-nAl6teTt7EWSjttNavAnv3uFR3w3vPP3OTYmHyPNHzKhAj2NoBDHmbS3MGpvvO8KXXPASnHjEGrrKrdKTMKPnQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.15.tgz", + "integrity": "sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^1.3.3" + "@inquirer/type": "^1.5.1" }, "engines": { "node": ">=18.0.0" @@ -5090,9 +4776,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.12.tgz", - "integrity": "sha512-vgTwzNUD3Hy4aqtGhX2+nV/usI0mwy3hDRuTjs8VcK0BLiMVEpNQXgzwlWEgPmA8AAPloUgyOs2nK5clJF5oIg==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.13.tgz", + "integrity": "sha512-uiKPB0Fv6WEEOZjruu9a6wnW/8jrjzlZbxXscMB8kuCJ1k6kHpcBnuvaAWcqhbI7rqX5GKziwWEdD+wi2gNLfA==", "cpu": [ "arm64" ], @@ -5104,9 +4790,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.12.tgz", - "integrity": "sha512-qOt0hAhj2ZLY6aEWu85rzt5zcyCAQITMhCMEPNlo1tuYekpVAdkQNiwXxEkCjBYvwTskvXuwXOOUpjuSc+aJnA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.13.tgz", + "integrity": "sha512-bEVIIfK5mSQoG1R19qA+fJOvCB+0wVGGnXHT3smchBVahYBdlPn2OsZZKzlHWfb1E+PhLBmYfqB5zQXFP7hJig==", "cpu": [ "x64" ], @@ -5118,9 +4804,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.12.tgz", - "integrity": "sha512-Ggd/UXpE+alMncbELCXA3OKpDj9bDBR3qVO7WRTxstloDglRAHfZmUJgTkeaNKjFO1JHqS7AKy0jba9XebZB1w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.13.tgz", + "integrity": "sha512-Yml1KlMzOnXj/tnW7yX8U78iAzTk39aILYvCPbqeewAq1kSzl+w59k/fiVkTBfvDi/oW/5YRxL+Fq+Y1Fr1r2Q==", "cpu": [ "arm" ], @@ -5132,9 +4818,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.12.tgz", - "integrity": "sha512-Qy4cFXFe9h1wAWMsojex8x1ifvw2kqiZv686YiRTdQEzAfc3vJASHFcD/QejHUCx7YHMYdnUoCS45rG2AiGDTQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.13.tgz", + "integrity": "sha512-afbVrsMgZ9dUTNUchFpj5VkmJRxvht/u335jUJ7o23YTbNbnpmXif3VKQGCtnjSh+CZaqm6N3CPG8KO3zwyZ1Q==", "cpu": [ "arm64" ], @@ -5146,9 +4832,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.12.tgz", - "integrity": "sha512-c+noT9IofktxktFllKHFmci8ka2SYGSLN17pj/KSl1hg7mmfAiGp4xxFxEwMLTb+SX95vP1DFiR++1I3WLVxvA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.13.tgz", + "integrity": "sha512-vOtxu0xC0SLdQ2WRXg8Qgd8T32ak4SPqk5zjItRszrJk2BdeXqfGxBJbP7o4aOvSPSmSSv46Lr1EP4HXU8v7Kg==", "cpu": [ "x64" ], @@ -5160,9 +4846,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.12.tgz", - "integrity": "sha512-CO3MFV8gUx16NU/CyyuumAKblESwvoGVA2XhQKZ976OTOxaTbb8F8D3f0iiZ4MYqsN74jIrFuCmXpPnpjbhfOQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.13.tgz", + "integrity": "sha512-UCrMJQY/gJnOl3XgbWRZZUvGGBuKy6i0YNSptgMzHBjs+QYDYR1Mt/RLTOPy4fzzves65O1EDmlL//OzEqoLlA==", "cpu": [ "x64" ], @@ -5302,18 +4988,6 @@ "win32" ] }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", - "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emnapi/core": "^1.1.0", - "@emnapi/runtime": "^1.1.0", - "@tybys/wasm-util": "^0.9.0" - } - }, "node_modules/@ng-bootstrap/ng-bootstrap": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-17.0.0.tgz", @@ -5332,9 +5006,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.1.4.tgz", - "integrity": "sha512-suoeZjd+7qd3ivzbNGGSzHtY/WMxTKU6ZD1gIIya0Un8Ve1eVxfq6Si6ReKqhygO8zN3paJMATn8sMmAV7qVrw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.0.tgz", + "integrity": "sha512-a6hbkYzh/KUlI52huiU4vztqIuxzyddg6kJGcelUJx3Ju6MJeziu+XmJ6wqFRvfH89zmJeaSADKsGFQaBHtJLg==", "dev": true, "license": "MIT", "engines": { @@ -5570,22 +5244,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/package-json/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@npmcli/promise-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", @@ -5679,221 +5337,6 @@ "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@nrwl/devkit": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.5.7.tgz", - "integrity": "sha512-sTEwqsAT6bMturU14o/0O6v509OkwGOglxpbiL/zIYO/fDkMoNgnhlHBIT87i4YVuofMz2Z+hTfjDskzDPRSYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nx/devkit": "19.5.7" - } - }, - "node_modules/@nrwl/tao": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.5.7.tgz", - "integrity": "sha512-c1rN6HY97+cEwoM5Q9412399Ac1rw7pI/3IS5iJSYkeI5TTGOobIpdCavJPZVcfqo4+wegXPA3F/OmulgbOUJA==", - "dev": true, - "license": "MIT", - "dependencies": { - "nx": "19.5.7", - "tslib": "^2.3.0" - }, - "bin": { - "tao": "index.js" - } - }, - "node_modules/@nx/devkit": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.5.7.tgz", - "integrity": "sha512-mUtZQcdqbF0Q9HfyG14jmpPCtZ1GnVaLNIADZv5SLpFyfh4ZjaBw6wdjPj7Sp3imLoyqMrcd9nCRNO2hlem8bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nrwl/devkit": "19.5.7", - "ejs": "^3.1.7", - "enquirer": "~2.3.6", - "ignore": "^5.0.4", - "minimatch": "9.0.3", - "semver": "^7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0", - "yargs-parser": "21.1.1" - }, - "peerDependencies": { - "nx": ">= 17 <= 20" - } - }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.5.7.tgz", - "integrity": "sha512-5jFAZSfV8QVNoxOXayZw4/jNJbxMMctNOYZW8Qj4eU8Ti+OmhsLgouxz/9enCh5SDITriOMZ7IHZ9rhrlGQoig==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-darwin-x64": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.5.7.tgz", - "integrity": "sha512-Ss+rF2+MQxyKrNnSYAeEGhtdE9hUHiTqyjJo4n1lvIWJ++TairOCtk5QRHrYLgAxE1XTf0OabcsDzegxv7yk3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.5.7.tgz", - "integrity": "sha512-FMLXcUr3mw/v4LvmNqHMAXy2k+T/hp2YpdBUq9ExteMfRywFsnKNlm39n/quniFsgKthEMdvvzxSQppRKaVwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.5.7.tgz", - "integrity": "sha512-LhJ342HutpR258lBLVTkXd6x2Uj4ZPJ6xKdfEm+FYQvG1byPr2L0TlNXcfSBkYtd7wRn0qg9eQZoCV/5+w415Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.5.7.tgz", - "integrity": "sha512-Q6gN+VNLisg7mYPTXC5JuGCP/s9tLjJFclKdH6FoP5K1Hgy88KK1uUoivDIfI8xaEgyLqphD1AAqokiFWZNWsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.5.7.tgz", - "integrity": "sha512-BsYNcYujNKb+uE7PrJp4PrX8a3G9oy+THaUr0t5+L435HjuZDBiK+tK9JzYGvM0bR5FOYm5K99I1DVD/Hv0snw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.5.7.tgz", - "integrity": "sha512-ILaLU8b5lUokYVF3vxAVj62qFok1hexiNzBdLGJPI1OkPGELtLyb8RymI3939iJoNMk1DS3/6dqK7NHXvHX8Mw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.5.7.tgz", - "integrity": "sha512-LfTnO4JZebLugioMk+GTptv3N38Wj2i2Pko0bdRZaKba+INGSlUgFqoRuO0KqZEmVIUGrxfkfqIN3HghVQ4D/Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.5.7.tgz", - "integrity": "sha512-cCTttdbf1AKuDU8j108SpIMWs53A/0mOVDPOPpa+oKkvBaI8ruZkxOceMjWZjWULd2gi1nS+5nJePpbrdQ8mkg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.5.7.tgz", - "integrity": "sha512-EqSnjpq1PNR/C8/YkL+Gn79dDfQ+HwJM8VJOt4qoCOQ9gQZqNJphjW2hg0H8WxLYezMScx3fbL99mvJO7ab2Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -5986,9 +5429,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", - "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", "cpu": [ "arm" ], @@ -6000,9 +5443,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", - "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", "cpu": [ "arm64" ], @@ -6014,9 +5457,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", - "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", "cpu": [ "arm64" ], @@ -6028,9 +5471,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", - "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", "cpu": [ "x64" ], @@ -6042,9 +5485,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", - "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", "cpu": [ "arm" ], @@ -6056,9 +5499,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", - "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", "cpu": [ "arm" ], @@ -6070,9 +5513,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", - "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", "cpu": [ "arm64" ], @@ -6084,9 +5527,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", - "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", "cpu": [ "arm64" ], @@ -6098,9 +5541,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", - "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", "cpu": [ "ppc64" ], @@ -6112,9 +5555,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", - "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", "cpu": [ "riscv64" ], @@ -6126,9 +5569,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", - "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", "cpu": [ "s390x" ], @@ -6140,9 +5583,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", - "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", "cpu": [ "x64" ], @@ -6154,9 +5597,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", - "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", "cpu": [ "x64" ], @@ -6168,9 +5611,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", - "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", "cpu": [ "arm64" ], @@ -6182,9 +5625,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", - "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", "cpu": [ "ia32" ], @@ -6196,9 +5639,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", - "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", "cpu": [ "x64" ], @@ -6210,14 +5653,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "18.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.4.tgz", - "integrity": "sha512-M3edVYKiAGWAAKs7XDLpz1OKUy4STVMT+46Y44ydYz06hI8m/dJfS8ZHTvXPl7JhkrIrSDEMed+WidZtGPIxMg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.0.tgz", + "integrity": "sha512-XePvx2ZnxCcAQw5lHVMUrJvm8MXqAWGcMyJDAuQUqNZrPCk3GpCaplWx2n+nPkinYVX2Q2v/DqtvWStQwgU4nA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.4", - "@angular-devkit/schematics": "18.1.4", + "@angular-devkit/core": "18.2.0", + "@angular-devkit/schematics": "18.2.0", "jsonc-parser": "3.3.1" }, "engines": { @@ -6227,73 +5670,73 @@ } }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.25.0.tgz", - "integrity": "sha512-nlWgp1lVhNQOTUplW85G3qm0fOIgAhJ/sl/31OIuScVrITYhYDF2bO+Zv/jQ8YsdUBAUXqY1tPT9wwPJklnPhw==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.26.0.tgz", + "integrity": "sha512-O2Tj+WK33/ZVp5STnz6ZL0OO+/Idk2KqsH0ITQkQmyZ2z0kdzWOeqK7s7q3/My6rB1GfPcyqPcBBv4dVv92FYQ==", "license": "MIT", "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.25.0.tgz", - "integrity": "sha512-327I5XJAFrsgjc5qUKxZ9rff3WNCfGvf1fIii70LQ2YQhQgG4XHZILmkD06ETEyXb+H1tkrNQQEJ1/d4ai+q5g==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.26.0.tgz", + "integrity": "sha512-hQtw1gg8n6ERK1UH47F7ZI1zOsbhu0J2VX+TrnkpaQR2FgxDW1oe9Ja6oCV4CQKuR4w+1ZI/Kj4imSt0K33kEw==", "license": "MIT", "dependencies": { - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.25.0.tgz", - "integrity": "sha512-3f7x8EYthyj157uV9V8vBjun+1gJnHhh2+i0qxYLhMGx7N2Fq0J3Bvvo1rosSg+fYh5HzPNZDufwIRdg5C/MQw==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.26.0.tgz", + "integrity": "sha512-JDY7W2bswlp5c3483lKP4kcb75fHNwGNfwD8x8FsY9xMjv7nxeXjLpR5cCEk1XqPq2+n6w4j7mJOXhEXGiUIKg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/browser-utils": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.25.0.tgz", - "integrity": "sha512-dPXlkAbkFL1DBum8rGTaHS+apJKaXEZJF9gLcBBKTruhTCizrugFLxajzIfVSiFVuwNKuJWa2fzhzbeQM0ee7w==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.26.0.tgz", + "integrity": "sha512-2CFQW6f9aJHIo/DqmqYa9PaYoLn1o36ywc0h8oyGrD4oPCbrnE5F++PmTdc71GBODu41HBn/yoCTLmxOD+UjpA==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/replay": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/angular": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/angular/-/angular-8.25.0.tgz", - "integrity": "sha512-sOHQrmD9B0adZxKTKs7CS0PaEShOBYRoCKOGjNx0iCEpPiswHHi9DzpniRYk1vNIL3Z0O7/eWoudnBojZNs8/g==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry/angular/-/angular-8.26.0.tgz", + "integrity": "sha512-9YolcJMdEzS6hbImal3jrAbzGZGM7DpmfSOfzt1Cs4bYTD9gCxKRkLyUgiNRIlrIBO7CkdpMrCSY+nEohvCw7A==", "license": "MIT", "dependencies": { - "@sentry/browser": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0", + "@sentry/browser": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0", "tslib": "^2.4.1" }, "engines": { @@ -6307,52 +5750,52 @@ } }, "node_modules/@sentry/browser": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.25.0.tgz", - "integrity": "sha512-51bdVGXjyooqVGzaSGsnExqRTt9NvZ1zGFsxbbCSXi5UoEFN6zdMUz6jKYsL2K80eeELP2VKOVlobHlEzeJQfw==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.26.0.tgz", + "integrity": "sha512-e5s6eKlwLZWzTwQcBwqyAGZMMuQROW9Z677VzwkSyREWAIkKjfH2VBxHATnNGc0IVkNHjD7iH3ixo3C0rLKM3w==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.25.0", - "@sentry-internal/feedback": "8.25.0", - "@sentry-internal/replay": "8.25.0", - "@sentry-internal/replay-canvas": "8.25.0", - "@sentry/core": "8.25.0", - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry-internal/browser-utils": "8.26.0", + "@sentry-internal/feedback": "8.26.0", + "@sentry-internal/replay": "8.26.0", + "@sentry-internal/replay-canvas": "8.26.0", + "@sentry/core": "8.26.0", + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.25.0.tgz", - "integrity": "sha512-7KtglbrW1eX4DOHkf6i4rRIExEf2CgtQ99qZ8gn5FUaAmNMg0rK7bb1yZMx0RZtp5G1TSz/S0jQQgxHWebaEig==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.26.0.tgz", + "integrity": "sha512-g/tVmTZD4GNbLFf++hKJfBpcCAtduFEMLnbfa9iT/QEZjlmP+EzY+GsH9bafM5VsNe8DiOUp+kJKWtShzlVdBA==", "license": "MIT", "dependencies": { - "@sentry/types": "8.25.0", - "@sentry/utils": "8.25.0" + "@sentry/types": "8.26.0", + "@sentry/utils": "8.26.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/types": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.25.0.tgz", - "integrity": "sha512-ojim0gDcRhGJPguYrtms4FsprX4xZz3LGNk9Z0hwTbSVEdlhQIInsQ7CYcdM3sjUs+qT7kfpxTRZGUeZNRRJcA==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.26.0.tgz", + "integrity": "sha512-zKmh6SWsJh630rpt7a9vP4Cm4m1C2gDTUqUiH565CajCL/4cePpNWYrNwalSqsOSL7B9OrczA1+n6a6XvND+ng==", "license": "MIT", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.25.0.tgz", - "integrity": "sha512-mVlkV7S62ZZ2jM38/kOwWx2xoW8fUv2cjw2IwFKoAIPyLBh3mo1WJtvfdtN/rXGjQWZJBKW53EWaWnD00rkjyA==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.26.0.tgz", + "integrity": "sha512-xvlPU9Hd2BlyT+FhWHGNwnxWqdVRk2AHnDtVcW4Ma0Ri5EwS+uy4Jeik5UkSv8C5RVb9VlxFmS8LN3I1MPJsLw==", "license": "MIT", "dependencies": { - "@sentry/types": "8.25.0" + "@sentry/types": "8.26.0" }, "engines": { "node": ">=14.18" @@ -6654,32 +6097,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@tufjs/models/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -6981,13 +6398,13 @@ } }, "node_modules/@types/node": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", - "integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", + "version": "22.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.3.0.tgz", + "integrity": "sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.13.0" + "undici-types": "~6.18.2" } }, "node_modules/@types/node-forge": { @@ -7335,22 +6752,6 @@ } } }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz", @@ -7593,72 +6994,14 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, + "license": "ISC", "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@yarnpkg/parsers/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", - "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/accepts": { @@ -7784,16 +7127,16 @@ } }, "node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -7972,9 +7315,9 @@ "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, "funding": [ { @@ -7992,11 +7335,11 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -8009,18 +7352,6 @@ "postcss": "^8.1.0" } }, - "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -8268,24 +7599,27 @@ } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -8657,22 +7991,6 @@ "dev": true, "license": "ISC" }, - "node_modules/cacache/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -10365,42 +9683,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz", - "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true, - "license": "MIT" - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -10432,9 +9714,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.8.tgz", + "integrity": "sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A==", "license": "ISC" }, "node_modules/emittery": { @@ -10502,16 +9784,6 @@ "node": ">=0.10.0" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -10526,19 +9798,6 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -10637,9 +9896,9 @@ "license": "MIT" }, "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.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10647,45 +9906,46 @@ "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.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/esbuild-wasm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.21.5.tgz", - "integrity": "sha512-L/FlOPMMFtw+6qPAbuPvJXdrOYOp9yx/PEwSrIZW0qghY4vgV003evdYDwqQ/9ENMQI0B6RMod9xT4FHtto6OQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.23.0.tgz", + "integrity": "sha512-6jP8UmWy6R6TUUV8bMuC3ZyZ6lZKI56x0tkxyCIqWwRRJ/DgeQKneh/Oid5EoGoPFLrGNkz47ZEtWAYuiY/u9g==", "dev": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/escalade": { @@ -10904,22 +10164,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-deprecation/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/eslint-plugin-jest": { "version": "28.8.0", "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", @@ -11594,19 +10838,6 @@ "node": ">=4" } }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -11657,6 +10888,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true, + "license": "MIT" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -11694,22 +10932,6 @@ "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", "license": "MIT" }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -11972,69 +11194,6 @@ "node": ">= 0.6" } }, - "node_modules/front-matter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", - "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1" - } - }, - "node_modules/front-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/front-matter/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/front-matter/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -12691,9 +11850,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -13227,9 +12386,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", - "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "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": { @@ -15427,19 +14586,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -15683,19 +14829,16 @@ } }, "node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } + "license": "MIT" }, "node_modules/lint-staged": { - "version": "15.2.8", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.8.tgz", - "integrity": "sha512-PUWFf2zQzsd9EFU+kM1d7UP+AZDbKFKuj+9JNVTBkhUFhbg4MAt6WfyMMwBfM4lYqd4D2Jwac5iuTu9rVj4zCQ==", + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -15720,32 +14863,6 @@ "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lint-staged/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/lint-staged/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -15759,13 +14876,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lint-staged/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" - }, "node_modules/lint-staged/node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -15826,24 +14936,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/listr2": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", - "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/lint-staged/node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -15902,22 +14994,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -15931,35 +15007,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -16035,9 +15093,9 @@ } }, "node_modules/lmdb": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.12.tgz", - "integrity": "sha512-JnoEulTgveoC64vlYJ9sufGLuNkk6TcxSYpKxSC9aM42I61jIv3pQH0fgb6qW7HV0+FNqA3g1WCQQYfhfawGoQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.13.tgz", + "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -16052,12 +15110,12 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.0.12", - "@lmdb/lmdb-darwin-x64": "3.0.12", - "@lmdb/lmdb-linux-arm": "3.0.12", - "@lmdb/lmdb-linux-arm64": "3.0.12", - "@lmdb/lmdb-linux-x64": "3.0.12", - "@lmdb/lmdb-win32-x64": "3.0.12" + "@lmdb/lmdb-darwin-arm64": "3.0.13", + "@lmdb/lmdb-darwin-x64": "3.0.13", + "@lmdb/lmdb-linux-arm": "3.0.13", + "@lmdb/lmdb-linux-arm64": "3.0.13", + "@lmdb/lmdb-linux-x64": "3.0.13", + "@lmdb/lmdb-win32-x64": "3.0.13" } }, "node_modules/loader-runner": { @@ -16373,13 +15431,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "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.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -16621,9 +15679,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -17186,22 +16244,6 @@ "node": ">=16" } }, - "node_modules/node-gyp/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -17225,13 +16267,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true, - "license": "MIT" - }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -17325,9 +16360,9 @@ } }, "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, "license": "ISC", "dependencies": { @@ -17354,9 +16389,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "license": "ISC", "dependencies": { @@ -17422,80 +16457,146 @@ "dev": true, "license": "MIT" }, - "node_modules/nx": { - "version": "19.5.7", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.5.7.tgz", - "integrity": "sha512-AUmGgE19NB4m/7oHYQVdzZHtclVevD8w0/nNzzjDJE823T8oeoNhmc9MfCLz+/2l2KOp+Wqm+8LiG9/xWpXk0g==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { - "@napi-rs/wasm-runtime": "0.2.4", - "@nrwl/tao": "19.5.7", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.7", - "axios": "^1.7.2", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "front-matter": "^4.0.2", - "fs-extra": "^11.1.0", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" + "ee-first": "1.1.1" }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.5.7", - "@nx/nx-darwin-x64": "19.5.7", - "@nx/nx-freebsd-x64": "19.5.7", - "@nx/nx-linux-arm-gnueabihf": "19.5.7", - "@nx/nx-linux-arm64-gnu": "19.5.7", - "@nx/nx-linux-arm64-musl": "19.5.7", - "@nx/nx-linux-x64-gnu": "19.5.7", - "@nx/nx-linux-x64-musl": "19.5.7", - "@nx/nx-win32-arm64-msvc": "19.5.7", - "@nx/nx-win32-x64-msvc": "19.5.7" + "engines": { + "node": ">=6" }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/nx/node_modules/ansi-styles": { + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -17511,7 +16612,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nx/node_modules/chalk": { + "node_modules/ora/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -17528,7 +16629,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/nx/node_modules/cli-cursor": { + "node_modules/ora/node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", @@ -17541,23 +16642,10 @@ "node": ">=8" } }, - "node_modules/nx/node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nx/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -17567,31 +16655,14 @@ "node": ">=7.0.0" } }, - "node_modules/nx/node_modules/color-name": { + "node_modules/ora/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, - "node_modules/nx/node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/nx/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/nx/node_modules/has-flag": { + "node_modules/ora/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -17601,85 +16672,65 @@ "node": ">=8" } }, - "node_modules/nx/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/ora/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/nx/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/nx/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "node_modules/ordered-binary": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", + "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", "dev": true, "license": "MIT" }, - "node_modules/nx/node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" @@ -17688,1210 +16739,865 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/nx/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "aggregate-error": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true, - "license": "MIT" + "license": "BlueOak-1.0.0" }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/pacote": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ee-first": "1.1.1" + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^8.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" }, "engines": { - "node": ">= 0.8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "wrappy": "1" + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "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": ">= 0.10" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "devOptional": true, "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "entities": "^4.4.0" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, "license": "MIT", "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "parse5": "^7.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/ora/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, "engines": { "node": ">=8" } }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/ora/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ora/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { "node": ">=8" } }, - "node_modules/ordered-binary": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", - "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", - "dev": true, + "node_modules/pepjs": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/pepjs/-/pepjs-0.5.3.tgz", + "integrity": "sha512-5yHVB9OHqKd9fr/OIsn8ss0NgThQ9buaqrEuwr9Or5YjPp6h+WTDKWZI+xZLaBGZCtODTnFtlSHNmhFsq67THg==", "license": "MIT" }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" + }, + "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": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, + "optional": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/p-retry": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", - "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "node_modules/piscina": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", + "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "license": "MIT", "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" + "find-up": "^6.3.0" }, "engines": { - "node": ">=16.17" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, "engines": { - "node": ">= 4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/pacote": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", - "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", - "dev": true, - "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/package-json": "^5.1.0", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^8.0.0", - "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^17.0.0", - "proc-log": "^4.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^2.2.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "bin/index.js" + "p-locate": "^6.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/papaparse": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", - "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", - "license": "MIT" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-json/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/parse-json/node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "devOptional": true, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, "license": "MIT", - "dependencies": { - "entities": "^4.4.0" + "engines": { + "node": ">=12.20" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse5-html-rewriting-stream": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", - "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "node_modules/postcss": { + "version": "8.4.40", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", + "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "entities": "^4.3.0", - "parse5": "^7.0.0", - "parse5-sax-parser": "^7.0.0" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/parse5-sax-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", - "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", "dev": true, "license": "MIT", "dependencies": { - "parse5": "^7.0.0" + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { + "node_modules/postcss-modules-values": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pepjs": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/pepjs/-/pepjs-0.5.3.tgz", - "integrity": "sha512-5yHVB9OHqKd9fr/OIsn8ss0NgThQ9buaqrEuwr9Or5YjPp6h+WTDKWZI+xZLaBGZCtODTnFtlSHNmhFsq67THg==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">=0.10" + "node": ">=4" } }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/posthog-js": { + "version": "1.155.4", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.155.4.tgz", + "integrity": "sha512-suxwAsmZGqMDXJe/RaCKI3PaDEHiuMDDhKcJklgGAg7eDnywieRkr5CoPcOOvnqTDMnuOPETr98jpYBXKUwGFQ==", "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" + "dependencies": { + "fflate": "^0.4.8", + "preact": "^10.19.3", + "web-vitals": "^4.0.1" } }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, + "node_modules/preact": { + "version": "10.23.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.23.2.tgz", + "integrity": "sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==", "license": "MIT", - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" } }, - "node_modules/piscina": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", - "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "optionalDependencies": { - "nice-napi": "^1.0.2" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "license": "MIT", - "dependencies": { - "find-up": "^6.3.0" + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=14.16" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "fast-diff": "^1.1.2" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^6.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^4.0.0" - }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "license": "ISC", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } + "license": "ISC" }, - "node_modules/pkg-dir/node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.20" + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "node_modules/postcss": { - "version": "8.4.40", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", - "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 6" } }, - "node_modules/postcss-loader": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", - "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", - "dev": true, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { - "cosmiconfig": "^9.0.0", - "jiti": "^1.20.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 0.10" } }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, + "license": "MIT", "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 0.10" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "license": "ISC", - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } + "license": "MIT", + "optional": true }, - "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT" }, - "node_modules/posthog-js": { - "version": "1.155.0", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.155.0.tgz", - "integrity": "sha512-gxi72Qcp7Vnq6efe5gNxsq84zyEFd33NUmoLSgcbMPhxU30qgc89Aw/N2mRB4mGrD3Mq0rCnDJUzGFdN59nR0g==", - "license": "MIT", + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "fflate": "^0.4.8", - "preact": "^10.19.3", - "web-vitals": "^4.0.1" - } - }, - "node_modules/preact": { - "version": "10.23.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.23.1.tgz", - "integrity": "sha512-O5UdRsNh4vdZaTieWe3XOgSpdMAmkIYBCT3VhQDlKrzyCm8lUYsk0fmVEvoQQifoOjFRTaHZO69ylrzTW2BH+A==", - "license": "MIT", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, - "license": "MIT" - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/querystringify": { @@ -19474,26 +18180,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/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": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, "license": "MIT", "dependencies": { @@ -19507,22 +18197,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", "fsevents": "~2.3.2" } }, @@ -19610,9 +18300,9 @@ } }, "node_modules/sass-loader": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.2.1.tgz", - "integrity": "sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.0.tgz", + "integrity": "sha512-n13Z+3rU9A177dk4888czcVFiC8CL9dii4qpXWUg3YIIgZEvi9TCFKjOQcbK0kJM7DJu9VucrZFddvNfYCPwtw==", "dev": true, "license": "MIT", "dependencies": { @@ -20606,24 +19296,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/styled-components": { "version": "5.3.11", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", @@ -20741,49 +19413,17 @@ "node": ">=10" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "minipass": "^3.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" + "node": ">= 8" } }, "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { @@ -20817,9 +19457,9 @@ "license": "ISC" }, "node_modules/terser": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", - "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -21030,13 +19670,6 @@ "tslib": "^2" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -21051,13 +19684,16 @@ "license": "MIT" }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, "engines": { - "node": ">=14.14" + "node": ">=0.6.0" } }, "node_modules/tmpl": { @@ -21114,16 +19750,6 @@ "node": ">=6" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/tr46": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", @@ -21458,332 +20084,756 @@ "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", "license": "MIT", - "dependencies": { - "typescript-compare": "^0.0.2" + "dependencies": { + "typescript-compare": "^0.0.2" + } + }, + "node_modules/undici-types": { + "version": "6.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", + "integrity": "sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", + "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.40", + "rollup": "^4.13.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/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==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" } }, - "node_modules/undici": { - "version": "6.19.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.5.tgz", - "integrity": "sha512-LryC15SWzqQsREHIOUybavaIHF5IoL0dJ9aWWxL/PgT1KfqAW5225FZpDUFlt9xiDMS2/S7DOKhFWA7RLksWdg==", + "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==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=18.17" + "node": ">=12" } }, - "node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "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==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "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==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "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==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "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==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "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==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "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==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "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==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "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==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 10.0.0" + "node": ">=12" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "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==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "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==", + "cpu": [ + "loong64" ], + "dev": true, "license": "MIT", - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "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==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "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==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "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==", + "cpu": [ + "riscv64" + ], + "dev": true, "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "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==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4.0" + "node": ">=12" } }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" + "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==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "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==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "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==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=10.12.0" + "node": ">=12" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "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==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "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==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/validate-npm-package-name": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", - "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "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==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "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==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/vite": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz", - "integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==", + "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, "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" - }, "bin": { - "vite": "bin/vite.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" + "node": ">=12" }, "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } + "@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/w3c-xmlserializer": { @@ -21924,9 +20974,9 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", "dev": true, "license": "MIT", "dependencies": { @@ -22087,18 +21137,18 @@ } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { diff --git a/package.json b/package.json index 614ce711c400..d48bfbed97b5 100644 --- a/package.json +++ b/package.json @@ -13,18 +13,18 @@ "node_modules" ], "dependencies": { - "@angular/animations": "18.1.4", - "@angular/cdk": "18.1.4", - "@angular/common": "18.1.4", - "@angular/compiler": "18.1.4", - "@angular/core": "18.1.4", - "@angular/forms": "18.1.4", - "@angular/localize": "18.1.4", - "@angular/material": "18.1.4", - "@angular/platform-browser": "18.1.4", - "@angular/platform-browser-dynamic": "18.1.4", - "@angular/router": "18.1.4", - "@angular/service-worker": "18.1.4", + "@angular/animations": "18.2.0", + "@angular/cdk": "18.2.0", + "@angular/common": "18.2.0", + "@angular/compiler": "18.2.0", + "@angular/core": "18.2.0", + "@angular/forms": "18.2.0", + "@angular/localize": "18.2.0", + "@angular/material": "18.2.0", + "@angular/platform-browser": "18.2.0", + "@angular/platform-browser-dynamic": "18.2.0", + "@angular/router": "18.2.0", + "@angular/service-worker": "18.2.0", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.1.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -37,7 +37,7 @@ "@ng-bootstrap/ng-bootstrap": "17.0.0", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", - "@sentry/angular": "8.25.0", + "@sentry/angular": "8.26.0", "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", @@ -64,7 +64,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.0", + "posthog-js": "1.155.4", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -110,7 +110,6 @@ }, "tough-cookie": "4.1.4", "undici": "6.19.5", - "vite": "5.3.5", "webpack-dev-middleware": "7.3.0", "word-wrap": "1.2.5", "ws": "8.18.0", @@ -118,22 +117,22 @@ }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.1.4", - "@angular-eslint/builder": "18.2.0", - "@angular-eslint/eslint-plugin": "18.2.0", - "@angular-eslint/eslint-plugin-template": "18.2.0", - "@angular-eslint/schematics": "18.2.0", - "@angular-eslint/template-parser": "18.2.0", - "@angular/cli": "18.1.4", - "@angular/compiler-cli": "18.1.4", - "@angular/language-service": "18.1.4", - "@sentry/types": "8.25.0", + "@angular-devkit/build-angular": "18.2.0", + "@angular-eslint/builder": "18.3.0", + "@angular-eslint/eslint-plugin": "18.3.0", + "@angular-eslint/eslint-plugin-template": "18.3.0", + "@angular-eslint/schematics": "18.3.0", + "@angular-eslint/template-parser": "18.3.0", + "@angular/cli": "18.2.0", + "@angular/compiler-cli": "18.2.0", + "@angular/language-service": "18.2.0", + "@sentry/types": "8.26.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.2.0", + "@types/node": "22.3.0", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", @@ -156,7 +155,7 @@ "jest-fail-on-console": "3.3.0", "jest-junit": "16.0.0", "jest-preset-angular": "14.2.2", - "lint-staged": "15.2.8", + "lint-staged": "15.2.9", "ng-mocks": "14.13.0", "prettier": "3.3.3", "sass": "1.77.8", diff --git a/src/main/webapp/app/course/competencies/competency-rings/competency-rings.component.scss b/src/main/webapp/app/course/competencies/competency-rings/competency-rings.component.scss index 48cbdc56eb9e..530831419029 100644 --- a/src/main/webapp/app/course/competencies/competency-rings/competency-rings.component.scss +++ b/src/main/webapp/app/course/competencies/competency-rings/competency-rings.component.scss @@ -17,13 +17,14 @@ svg { transform-origin: 50%; } .progressbar { + stroke-linecap: round; + &-anim { animation: ring-appear 1s ease-in-out forwards; transition: stroke-dasharray 1s ease-in-out, opacity 1s linear; } - stroke-linecap: round; &.hidden { // Use opacity: 0 instead of display: none to prevent animation when appearing @@ -56,11 +57,11 @@ svg { stroke: var(--competency-rings-green-bg); } .progressbar { + stroke: var(--competency-rings-green); &-anim { animation-duration: 1s; transition-duration: 1s; } - stroke: var(--competency-rings-green); } } } diff --git a/src/main/webapp/app/course/manage/overview/course-management-card.scss b/src/main/webapp/app/course/manage/overview/course-management-card.scss index 2d3561b67c33..d48a2845f0e7 100644 --- a/src/main/webapp/app/course/manage/overview/course-management-card.scss +++ b/src/main/webapp/app/course/manage/overview/course-management-card.scss @@ -17,13 +17,14 @@ transition: 0.15s; background-color: var(--background-color-for-hover) !important; - &:hover { - background-color: color-mix(in srgb, var(--background-color-for-hover), transparent 15%) !important; - } display: flex; cursor: pointer; height: 100px; + &:hover { + background-color: color-mix(in srgb, var(--background-color-for-hover), transparent 15%) !important; + } + > div { flex: 0 1 auto; } @@ -210,7 +211,11 @@ @media screen and (max-width: 850px) { .card { + height: unset; .card-heading { + height: unset; + max-height: 135px; + .card-header-left { flex-direction: column; max-width: 110px; @@ -244,12 +249,7 @@ display: flex; align-content: center; } - - height: unset; - max-height: 135px; } - - height: unset; } } diff --git a/src/main/webapp/app/exam/manage/students/exam-students.component.scss b/src/main/webapp/app/exam/manage/students/exam-students.component.scss index 821e828b9871..ae06ec2008e2 100644 --- a/src/main/webapp/app/exam/manage/students/exam-students.component.scss +++ b/src/main/webapp/app/exam/manage/students/exam-students.component.scss @@ -47,16 +47,16 @@ jhi-exam-students { &.newly-registered { $vars: map-get($datatable-row, newly-registered); + animation-name: flash-animation; + animation-delay: map-get($vars, animation-delay); + animation-duration: map-get($vars, animation-duration); + animation-timing-function: ease-out; + @keyframes flash-animation { 30% { background-color: map-get($vars, background-color); } } - - animation-name: flash-animation; - animation-delay: map-get($vars, animation-delay); - animation-duration: map-get($vars, animation-duration); - animation-timing-function: ease-out; } } } diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.scss b/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.scss index 225900c6b301..2fa141c0b0d4 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.scss +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.scss @@ -36,12 +36,12 @@ } .mat-expansion-panel.code-hint-creation-expansion-panel-wrapper-header { + font-weight: bold; + cursor: default; + .mat-expansion-panel-header { border-bottom: 2px solid; } - - font-weight: bold; - cursor: default; } .sort-icon { diff --git a/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.scss b/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.scss index a82c4ccbdcc1..152f84298691 100644 --- a/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.scss +++ b/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.scss @@ -25,16 +25,15 @@ .left-col { flex: 1 1 auto; + flex-direction: column; + min-width: 0; + display: flex; + gap: 5px; @supports (flex-basis: min-content) { flex: 1 1 min-content; } - min-width: 0; - display: flex; - flex-direction: column; - gap: 5px; - .title-row { display: flex; gap: 5px; diff --git a/src/main/webapp/app/exercises/shared/team/team-participate/team-students-online-list.component.scss b/src/main/webapp/app/exercises/shared/team/team-participate/team-students-online-list.component.scss index 574b3a2ed27f..f2535c3285e2 100644 --- a/src/main/webapp/app/exercises/shared/team/team-participate/team-students-online-list.component.scss +++ b/src/main/webapp/app/exercises/shared/team/team-participate/team-students-online-list.component.scss @@ -35,20 +35,20 @@ } .student-status { - @include status-change-transition; - display: inline-flex; color: var(--secondary); - } - .student-name { @include status-change-transition; + } + .student-name { max-width: 190px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color: var(--secondary); + + @include status-change-transition; } .online { diff --git a/src/main/webapp/app/grading-system/bonus/bonus.component.scss b/src/main/webapp/app/grading-system/bonus/bonus.component.scss index e4be0728ad57..609f5fcf18fd 100644 --- a/src/main/webapp/app/grading-system/bonus/bonus.component.scss +++ b/src/main/webapp/app/grading-system/bonus/bonus.component.scss @@ -8,11 +8,6 @@ $numbering-margin: calc($numbering-size / 2 - $numbering-border); // To make num } .bonus-form-step { - &::before { - counter-increment: bonus-step-counter; - content: counter(bonus-step-counter); - } - border-radius: $numbering-size; width: $numbering-size; height: $numbering-size; @@ -20,6 +15,11 @@ $numbering-margin: calc($numbering-size / 2 - $numbering-border); // To make num border: $numbering-border solid; text-align: center; margin-left: $numbering-margin; + + &::before { + counter-increment: bonus-step-counter; + content: counter(bonus-step-counter); + } } .bonus-calculated { diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-messages/conversation-messages.component.scss b/src/main/webapp/app/overview/course-conversations/layout/conversation-messages/conversation-messages.component.scss index 58d9f6d9f3f0..01f09f46008e 100644 --- a/src/main/webapp/app/overview/course-conversations/layout/conversation-messages/conversation-messages.component.scss +++ b/src/main/webapp/app/overview/course-conversations/layout/conversation-messages/conversation-messages.component.scss @@ -1,4 +1,9 @@ .conversation-messages { + --message-input-height-prod: 171px; + --message-input-height-dev: 187px; + --search-height: 52px; + --channel-header-height: 52px; + .search-active { input { border: 1px solid var(--primary); @@ -34,11 +39,6 @@ padding-top: 0.375rem !important; } - --message-input-height-prod: 171px; - --message-input-height-dev: 187px; - --search-height: 52px; - --channel-header-height: 52px; - .posting-infinite-scroll-container { max-height: calc(75vh - var(--message-input-height-prod) - var(--search-height) - var(--channel-header-height)); overflow-y: auto; diff --git a/src/main/webapp/app/overview/course-overview.scss b/src/main/webapp/app/overview/course-overview.scss index 1d8c2df40685..366470e3c500 100644 --- a/src/main/webapp/app/overview/course-overview.scss +++ b/src/main/webapp/app/overview/course-overview.scss @@ -141,6 +141,8 @@ canvas#complete-chart { text-align: left; color: white; background-color: #3e8acc; + border: none; + border-radius: 1px; &:hover { background-color: #0f6ab4; } @@ -150,8 +152,6 @@ canvas#complete-chart { &:disabled { background-color: gray; } - border: none; - border-radius: 1px; } /* Default the color to white even on bootstrap 5 */ diff --git a/src/main/webapp/app/shared/course-group/course-group.component.scss b/src/main/webapp/app/shared/course-group/course-group.component.scss index adae3ffdf4b9..28fbff8cc69c 100644 --- a/src/main/webapp/app/shared/course-group/course-group.component.scss +++ b/src/main/webapp/app/shared/course-group/course-group.component.scss @@ -47,16 +47,16 @@ jhi-course-group { &.newly-added-member { $vars: map-get($datatable-row, newly-added-member); + animation-name: flash-animation; + animation-delay: map-get($vars, animation-delay); + animation-duration: map-get($vars, animation-duration); + animation-timing-function: ease-out; + @keyframes flash-animation { 30% { background-color: map-get($vars, background-color); } } - - animation-name: flash-animation; - animation-delay: map-get($vars, animation-delay); - animation-duration: map-get($vars, animation-duration); - animation-timing-function: ease-out; } } } diff --git a/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.scss b/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.scss index d43b31093543..7e472d33e2e3 100644 --- a/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.scss +++ b/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.scss @@ -91,6 +91,9 @@ jhi-tutor-participation-graph { margin-bottom: 1rem; .stacked-item { + margin-top: 0.5em; + position: relative; + &:first-child { margin-top: 0; @@ -104,9 +107,6 @@ jhi-tutor-participation-graph { } } - margin-top: 0.5em; - position: relative; - &::before, &::after { content: ''; diff --git a/src/main/webapp/app/shared/sidebar/sidebar.component.scss b/src/main/webapp/app/shared/sidebar/sidebar.component.scss index ebfdd50cf1a6..7aa6c10477b1 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar.component.scss +++ b/src/main/webapp/app/shared/sidebar/sidebar.component.scss @@ -7,6 +7,7 @@ } .scrollable-item-content { + overflow-y: auto; height: calc(100vh - var(--sidebar-footer-height-prod) - var(--header-height) - var(--search-height)); &.content-height-dev { height: calc(100vh - var(--sidebar-footer-height-dev) - var(--header-height) - var(--search-height)); @@ -14,8 +15,6 @@ @media (max-width: 768px) { height: calc(100vh - var(--sidebar-footer-height-prod) - var(--header-height) - var(--search-height)) !important; } - - overflow-y: auto; } .sidebar { From f6b45e0fc2203f883d818bc1dd82d511205b64fa Mon Sep 17 00:00:00 2001 From: Jan Thurner <107639007+Jan-Thurner@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:54:18 +0200 Subject: [PATCH 02/60] Development: Analyze REST calls and endpoints (#8771) --- .../analysis-of-endpoint-connections.yml | 79 ++++--- settings.gradle | 1 + .../build.gradle | 24 +- ...{eslint.conjig.json => eslint.config.json} | 7 +- .../AnalysisOfEndpointConnections.java | 83 ------- .../endpointanalysis/EndpointAnalysis.java | 6 + .../endpointanalysis/EndpointAnalyzer.java | 144 ++++++++++++ .../EndpointClassInformation.java | 6 + .../endpointanalysis/EndpointInformation.java | 36 +++ .../cit/endpointanalysis/EndpointParser.java | 217 ++++++++++++++++++ .../endpointanalysis/RestCallAnalysis.java | 6 + .../endpointanalysis/RestCallAnalyzer.java | 144 ++++++++++++ .../RestCallFileInformation.java | 4 + .../endpointanalysis/RestCallInformation.java | 18 ++ .../RestCallWithMatchingEndpoint.java | 4 + .../cit/endpointanalysis/UsedEndpoints.java | 6 + .../AnalysisOfEndpointConnectionsClient.ts | 53 ++++- .../src/main/typeScript/Postprocessor.ts | 22 +- .../src/main/typeScript/Preprocessor.ts | 26 +-- 19 files changed, 729 insertions(+), 157 deletions(-) rename supporting_scripts/analysis-of-endpoint-connections/{eslint.conjig.json => eslint.config.json} (72%) delete mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java create mode 100644 supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java diff --git a/.github/workflows/analysis-of-endpoint-connections.yml b/.github/workflows/analysis-of-endpoint-connections.yml index 25849bddd012..2116605bea0a 100644 --- a/.github/workflows/analysis-of-endpoint-connections.yml +++ b/.github/workflows/analysis-of-endpoint-connections.yml @@ -1,12 +1,8 @@ +name: Analysis of Endpoint Connections + on: workflow_dispatch: - pull_request: - types: - - opened - - synchronize - paths: - - 'src/main/java/**' - - 'src/main/webapp/**' + push: # Keep in sync with build.yml and test.yml and codeql-analysis.yml env: @@ -15,7 +11,7 @@ env: java: 21 jobs: - analysis-of-endpoint-connections: + Parse-rest-calls-and-endpoints: timeout-minutes: 10 runs-on: ubuntu-latest steps: @@ -24,39 +20,70 @@ jobs: with: fetch-depth: 0 - - name: Get list of modified files - run: | - git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD > modified_files.txt + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '${{ env.java }}' + distribution: 'temurin' + cache: 'gradle' - # Analyze the client sided REST-API calls - - name: Set up Node.js + - name: Set up node.js uses: actions/setup-node@v4 with: node-version: '${{ env.node }}' - - name: Install and compile TypeScript + - name: Parse client sided REST-API calls run: | - cd supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/ npm install - tsc -p tsconfig.analysisOfEndpointConnections.json - - - name: Run analysis-of-endpoint-connections-client - run: | + tsc -p supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/tsconfig.analysisOfEndpointConnections.json node supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.js - - name: Upload JSON file + - name: Parse server sided Endpoints + run: ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runEndpointParser + + - name: Upload parsing results uses: actions/upload-artifact@v4 with: - name: rest-calls-json - path: supporting_scripts/analysis-of-endpoint-connections/restCalls.json + name: REST API Parsing Results + path: | + supporting_scripts/analysis-of-endpoint-connections/endpoints.json + supporting_scripts/analysis-of-endpoint-connections/restCalls.json + + Analysis-of-endpoint-connections: + needs: Parse-rest-calls-and-endpoints + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 - # Analyze the server sided endpoints - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '${{ env.java }}' + cache: 'gradle' - - name: Run analysis-of-endpoint-connections - run: | - ./gradlew :supporting_scripts:analysis-of-endpoint-connections:run --args="$(cat modified_files.txt)" + - name: Download JSON files + uses: actions/download-artifact@v4 + with: + name: REST API Parsing Results + path: supporting_scripts/analysis-of-endpoint-connections/ + + - name: Analyze endpoints + run: + ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runEndpointAnalysis + + - name: Analyze rest calls + run: + ./gradlew :supporting_scripts:analysis-of-endpoint-connections:runRestCallAnalysis + + - name: Upload analysis results + uses: actions/upload-artifact@v4 + with: + name: Endpoint and REST Call Analysis Results + path: | + supporting_scripts/analysis-of-endpoint-connections/endpointAnalysisResult.json + supporting_scripts/analysis-of-endpoint-connections/restCallAnalysisResult.json diff --git a/settings.gradle b/settings.gradle index b9f9d365979c..c99752089fcd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,6 +14,7 @@ pluginManagement { rootProject.name = 'Artemis' +// needed for rest call and endpoint analysis include 'supporting_scripts:analysis-of-endpoint-connections' // needed for programming exercise templates diff --git a/supporting_scripts/analysis-of-endpoint-connections/build.gradle b/supporting_scripts/analysis-of-endpoint-connections/build.gradle index ef2fa37c2f5a..0e41c785d65c 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/build.gradle +++ b/supporting_scripts/analysis-of-endpoint-connections/build.gradle @@ -13,20 +13,26 @@ repositories { evaluationDependsOn(':') dependencies { - implementation rootProject.ext.qDoxVersionReusable + implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.26.0' + implementation 'com.github.javaparser:javaparser-core:3.26.0' + implementation 'com.github.javaparser:javaparser-core-serialization:3.26.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' implementation rootProject.ext.springBootStarterWeb + implementation 'org.slf4j:slf4j-api:1.7.32' + implementation 'ch.qos.logback:logback-classic:1.2.6' } -test { - useJUnitPlatform() +task runEndpointParser(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.EndpointParser' } -application { - mainClassName = 'de.tum.cit.endpointanalysis.AnalysisOfEndpointConnections' +task runEndpointAnalysis(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.EndpointAnalyzer' } -run { - if (project.hasProperty('appArgs')) { - args = project.appArgs.split(' ') - } +task runRestCallAnalysis(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + mainClass = 'de.tum.cit.endpointanalysis.RestCallAnalyzer' } diff --git a/supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json b/supporting_scripts/analysis-of-endpoint-connections/eslint.config.json similarity index 72% rename from supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json rename to supporting_scripts/analysis-of-endpoint-connections/eslint.config.json index 0b47d7836035..393e1c0972cf 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/eslint.conjig.json +++ b/supporting_scripts/analysis-of-endpoint-connections/eslint.config.json @@ -10,10 +10,5 @@ "jsx": true } }, - "rules": {}, - "settings": { - "react": { - "version": "detect" - } - } + "rules": {} } diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java deleted file mode 100644 index b47b91d680d8..000000000000 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/AnalysisOfEndpointConnections.java +++ /dev/null @@ -1,83 +0,0 @@ -package de.tum.cit.endpointanalysis; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.thoughtworks.qdox.JavaProjectBuilder; -import com.thoughtworks.qdox.model.JavaAnnotation; -import com.thoughtworks.qdox.model.JavaClass; -import com.thoughtworks.qdox.model.JavaMethod; - -public class AnalysisOfEndpointConnections { - - /** - * This is the entry point of the analysis of server sided endpoints. - * - * @param args List of files that should be analyzed regarding endpoints. - */ - public static void main(String[] args) { - if (args.length == 0) { - System.out.println("No files to analyze."); - return; - } - String[] filePaths = args[0].split("\n"); - String[] serverFiles = Arrays.stream(filePaths).map(filePath -> Paths.get("..", "..", filePath).toString()) - .filter(filePath -> Files.exists(Paths.get(filePath)) && filePath.endsWith(".java")).toArray(String[]::new); - analyzeServerEndpoints(serverFiles); - } - - private static void analyzeServerEndpoints(String[] filePaths) { - final Set httpMethodClasses = Set.of(GetMapping.class.getName(), PostMapping.class.getName(), PutMapping.class.getName(), DeleteMapping.class.getName(), - PatchMapping.class.getName(), RequestMapping.class.getName()); - - JavaProjectBuilder builder = new JavaProjectBuilder(); - for (String filePath : filePaths) { - builder.addSourceTree(new File(filePath)); - } - - Collection classes = builder.getClasses(); - for (JavaClass javaClass : classes) { - Optional requestMappingOptional = javaClass.getAnnotations().stream() - .filter(annotation -> annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName())).findFirst(); - - boolean hasEndpoint = javaClass.getMethods().stream().flatMap(method -> method.getAnnotations().stream()) - .anyMatch(annotation -> httpMethodClasses.contains(annotation.getType().getFullyQualifiedName())); - - if (hasEndpoint) { - System.out.println("=================================================="); - System.out.println("Class: " + javaClass.getFullyQualifiedName()); - requestMappingOptional.ifPresent(annotation -> System.out.println("Class Request Mapping: " + annotation.getProperty("value"))); - System.out.println("=================================================="); - } - - for (JavaMethod method : javaClass.getMethods()) { - for (JavaAnnotation annotation : method.getAnnotations()) { - if (httpMethodClasses.contains(annotation.getType().getFullyQualifiedName())) { - System.out.println("Endpoint: " + method.getName()); - System.out.println( - annotation.getType().getFullyQualifiedName().equals(RequestMapping.class.getName()) ? "RequestMapping·method: " + annotation.getProperty("method") - : "HTTP method annotation: " + annotation.getType().getName()); - System.out.println("Path: " + annotation.getProperty("value")); - System.out.println("Line: " + method.getLineNumber()); - List annotations = method.getAnnotations().stream().filter(a -> !a.equals(annotation)).map(a -> a.getType().getName()).toList(); - System.out.println("Other annotations: " + annotations); - System.out.println("---------------------------------------------------"); - } - } - } - } - } -} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java new file mode 100644 index 000000000000..4c38f7e826e8 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalysis.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record EndpointAnalysis(List usedEndpoints, List unusedEndpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java new file mode 100644 index 000000000000..250966bfd432 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointAnalyzer.java @@ -0,0 +1,144 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class EndpointAnalyzer { + + private static String EndpointAnalysisResultPath = "endpointAnalysisResult.json"; + + private static final Logger logger = LoggerFactory.getLogger(EndpointAnalyzer.class); + + public static void main(String[] args) { + analyzeEndpoints(); + printEndpointAnalysisResult(); + } + + /** + * Analyzes server side endpoints and matches them with client side REST calls. + * + * This method reads endpoint and REST call information from JSON files, + * compares them to find matching REST calls for each endpoint, and writes + * the analysis result to a JSON file. Endpoints without matching REST calls + * are also recorded. + */ + private static void analyzeEndpoints() { + ObjectMapper mapper = new ObjectMapper(); + + try { + List endpointClasses = mapper.readValue(new File(EndpointParser.ENDPOINT_PARSING_RESULT_PATH), + new TypeReference>() { + }); + List restCallFiles = mapper.readValue(new File(EndpointParser.REST_CALL_PARSING_RESULT_PATH), + new TypeReference>() { + }); + + List endpointsAndMatchingRestCalls = new ArrayList<>(); + List unusedEndpoints = new ArrayList<>(); + + Map> restCallMap = new HashMap<>(); + + // Populate the map with rest calls + for (RestCallFileInformation restCallFile : restCallFiles) { + for (RestCallInformation restCall : restCallFile.restCalls()) { + String restCallURI = restCall.buildComparableRestCallUri(); + restCallMap.computeIfAbsent(restCallURI, uri -> new ArrayList<>()).add(restCall); + } + } + + for (EndpointClassInformation endpointClass : endpointClasses) { + for (EndpointInformation endpoint : endpointClass.endpoints()) { + + String endpointURI = endpoint.buildComparableEndpointUri(); + List matchingRestCalls = restCallMap.getOrDefault(endpointURI, new ArrayList<>()); + + // Check for wildcard endpoints if no exact match is found + checkForWildcardEndpoints(endpoint, matchingRestCalls, endpointURI, restCallMap); + + if (matchingRestCalls.isEmpty()) { + unusedEndpoints.add(endpoint); + } + else { + endpointsAndMatchingRestCalls.add(new UsedEndpoints(endpoint, matchingRestCalls, endpointClass.filePath())); + } + } + } + + EndpointAnalysis endpointAnalysis = new EndpointAnalysis(endpointsAndMatchingRestCalls, unusedEndpoints); + mapper.writeValue(new File(EndpointAnalysisResultPath), endpointAnalysis); + } + catch (IOException e) { + logger.error("Failed to analyze endpoints", e); + } + } + + /** + * Checks for wildcard endpoints and adds matching REST calls to the list. + * + * This method is used to find matching REST calls for endpoints that use wildcard URIs. + * If no exact match is found for an endpoint, it checks if the endpoint URI ends with a wildcard ('*'). + * It then iterates through the rest call map to find URIs that start with the same prefix as the endpoint URI + * (excluding the wildcard) and have the same HTTP method. If such URIs are found, they are added to the list of matching REST calls. + * + * @param endpoint The endpoint information to check for wildcard matches. + * @param matchingRestCalls The list of matching REST calls to be populated. + * @param endpointURI The URI of the endpoint being checked. + * @param restCallMap The map of rest call URIs to their corresponding information. + */ + private static void checkForWildcardEndpoints(EndpointInformation endpoint, List matchingRestCalls, String endpointURI, + Map> restCallMap) { + if (matchingRestCalls.isEmpty() && endpointURI.endsWith("*")) { + for (String uri : restCallMap.keySet()) { + if (uri.startsWith(endpoint.buildComparableEndpointUri().substring(0, endpoint.buildComparableEndpointUri().length() - 1)) + && endpoint.getHttpMethod().toLowerCase().equals(restCallMap.get(uri).get(0).method().toLowerCase())) { + matchingRestCalls.addAll(restCallMap.get(uri)); + } + } + } + } + + /** + * Prints the endpoint analysis result. + * + * This method reads the endpoint analysis result from a JSON file and prints + * the details of unused endpoints to the console. The details include the + * endpoint URI, HTTP method, file path, and line number. If no matching REST + * call is found for an endpoint, it prints a message indicating this. + */ + private static void printEndpointAnalysisResult() { + ObjectMapper mapper = new ObjectMapper(); + EndpointAnalysis endpointsAndMatchingRestCalls = null; + try { + endpointsAndMatchingRestCalls = mapper.readValue(new File(EndpointAnalysisResultPath), new TypeReference() { + }); + } + catch (IOException e) { + logger.error("Failed to deserialize endpoint analysis result", e); + return; + } + + endpointsAndMatchingRestCalls.unusedEndpoints().stream().forEach(endpoint -> { + logger.info("============================================="); + logger.info("Endpoint URI: {}", endpoint.buildCompleteEndpointURI()); + logger.info("HTTP method: {}", endpoint.httpMethodAnnotation()); + logger.info("File path: {}", endpoint.className()); + logger.info("Line: {}", endpoint.line()); + logger.info("============================================="); + logger.info("No matching REST call found for endpoint: {}", endpoint.buildCompleteEndpointURI()); + logger.info("---------------------------------------------"); + logger.info(""); + }); + + logger.info("Number of endpoints without matching REST calls: {}", endpointsAndMatchingRestCalls.unusedEndpoints().size()); + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java new file mode 100644 index 000000000000..062a3671b1bf --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointClassInformation.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record EndpointClassInformation(String filePath, String classRequestMapping, List endpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java new file mode 100644 index 000000000000..19b32dc8881b --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointInformation.java @@ -0,0 +1,36 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public record EndpointInformation(String requestMapping, String endpoint, String httpMethodAnnotation, String URI, String className, int line, List otherAnnotations) { + + public String buildCompleteEndpointURI() { + StringBuilder result = new StringBuilder(); + if (this.requestMapping != null && !this.requestMapping.isEmpty()) { + // Remove quotes from the requestMapping as they are used to define the String in the source code but are not part of the URI + result.append(this.requestMapping.replace("\"", "")); + } + // Remove quotes from the URI as they are used to define the String in the source code but are not part of the URI + result.append(this.URI.replace("\"", "")); + return result.toString(); + } + + String buildComparableEndpointUri() { + // Replace arguments with placeholder + return this.buildCompleteEndpointURI().replaceAll("\\{.*?\\}", ":param:"); + } + + @JsonIgnore + public String getHttpMethod() { + return switch (this.httpMethodAnnotation) { + case "GetMapping" -> "get"; + case "PostMapping" -> "post"; + case "PutMapping" -> "put"; + case "DeleteMapping" -> "delete"; + case "PatchMapping" -> "patch"; + default -> "No HTTP method annotation found"; + }; + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java new file mode 100644 index 000000000000..b0ab2cdb1f0b --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/EndpointParser.java @@ -0,0 +1,217 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.expr.ArrayInitializerExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.NormalAnnotationExpr; +import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr; + +public class EndpointParser { + + static final String ENDPOINT_PARSING_RESULT_PATH = "endpoints.json"; + + static final String REST_CALL_PARSING_RESULT_PATH = "restCalls.json"; + + private static final Logger logger = LoggerFactory.getLogger(EndpointParser.class); + + public static void main(String[] args) { + final Path absoluteDirectoryPath = Path.of("../../src/main/java").toAbsolutePath().normalize(); + + StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21); + + String[] filesToParse = {}; + try (Stream paths = Files.walk(absoluteDirectoryPath)) { + filesToParse = paths.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".java")).map(Path::toString).toArray(String[]::new); + } + catch (IOException e) { + logger.error("Error reading files from directory: {}", absoluteDirectoryPath, e); + } + + parseServerEndpoints(filesToParse); + } + + /** + * Parses server endpoints from the given file paths. + * + * This method reads Java files from the specified file paths, extracts endpoint + * information annotated with HTTP method annotations, and writes the parsed + * endpoint information to a JSON file. It also logs any files that failed to parse. + * + * @param filePaths an array of file paths to parse for endpoint information + */ + private static void parseServerEndpoints(String[] filePaths) { + List endpointClasses = new ArrayList<>(); + final Set httpMethodClasses = Set.of(GetMapping.class.getSimpleName(), PostMapping.class.getSimpleName(), PutMapping.class.getSimpleName(), + DeleteMapping.class.getSimpleName(), PatchMapping.class.getSimpleName(), RequestMapping.class.getSimpleName()); + List filesFailedToParse = new ArrayList<>(); + + for (String filePath : filePaths) { + CompilationUnit compilationUnit; + try { + compilationUnit = StaticJavaParser.parse(new File(filePath)); + } + catch (Exception e) { + filesFailedToParse.add(filePath); + continue; + } + + List classes = compilationUnit.findAll(ClassOrInterfaceDeclaration.class); + for (ClassOrInterfaceDeclaration javaClass : classes) { + List endpoints = new ArrayList<>(); + final String classRequestMappingString = extractClassRequestMapping(javaClass, httpMethodClasses); + + endpoints.addAll(extractAnnotationPathValues(javaClass, httpMethodClasses, classRequestMappingString)); + + if (!endpoints.isEmpty()) { + endpointClasses.add(new EndpointClassInformation(javaClass.getNameAsString(), classRequestMappingString, endpoints)); + } + } + } + + printFilesFailedToParse(filesFailedToParse); + + writeEndpointsToFile(endpointClasses); + } + + /** + * Extracts endpoint information from the methods of a given class declaration. + * + * This method iterates over the methods of the provided class and their annotations. + * If an annotation matches one of the specified HTTP method annotations, it extracts + * the path values from the annotation and creates EndpointInformation objects for each path. + * + * @param javaClass the class declaration to extract endpoint information from + * @param httpMethodClasses a set of HTTP method annotation class names + * @param classRequestMappingString the class-level request mapping string + * @return a list of EndpointInformation objects representing the extracted endpoint information + */ + private static List extractAnnotationPathValues(ClassOrInterfaceDeclaration javaClass, Set httpMethodClasses, String classRequestMappingString) { + return javaClass.getMethods().stream() + .flatMap(method -> method.getAnnotations().stream().filter(annotation -> httpMethodClasses.contains(annotation.getNameAsString())) + .flatMap(annotation -> extractPathsFromAnnotation(annotation).stream() + .map(path -> new EndpointInformation(classRequestMappingString, method.getNameAsString(), annotation.getNameAsString(), path, + javaClass.getNameAsString(), method.getBegin().get().line, method.getAnnotations().stream().map(AnnotationExpr::toString).toList())))) + .toList(); + } + + /** + * Extracts the paths from the given annotation. + * + * This method processes the provided annotation to extract path values. + * It handles both single-member and normal annotations, extracting the + * path values from the annotation's member values or pairs. + * + * @param annotation the annotation to extract paths from + * @return a list of extracted path values + */ + private static List extractPathsFromAnnotation(AnnotationExpr annotation) { + List paths = new ArrayList<>(); + if (annotation instanceof SingleMemberAnnotationExpr singleMemberAnnotationExpr) { + Expression memberValue = singleMemberAnnotationExpr.getMemberValue(); + if (memberValue instanceof ArrayInitializerExpr arrayInitializerExpr) { + paths.addAll(arrayInitializerExpr.getValues().stream().map(Expression::toString).collect(Collectors.toList())); + } + else { + paths.add(memberValue.toString()); + } + } + else if (annotation instanceof NormalAnnotationExpr normalAnnotationExpr) { + normalAnnotationExpr.getPairs().stream().filter(pair -> "value".equals(pair.getNameAsString())).forEach(pair -> paths.add(pair.getValue().toString())); + } + return paths; + } + + /** + * Extracts the class-level request mapping from a given class declaration. + * + * This method scans the annotations of the provided class to find a `RequestMapping` annotation. + * It then checks if the class contains any methods annotated with HTTP method annotations. + * If such methods are found, it extracts the value of the `RequestMapping` annotation. + * + * @param javaClass the class declaration to extract the request mapping from + * @param httpMethodClasses a set of HTTP method annotation class names + * @return the extracted request mapping value, or an empty string if no request mapping is found or the class has no HTTP method annotations + */ + private static String extractClassRequestMapping(ClassOrInterfaceDeclaration javaClass, Set httpMethodClasses) { + boolean hasEndpoint = javaClass.getMethods().stream().flatMap(method -> method.getAnnotations().stream()) + .anyMatch(annotation -> httpMethodClasses.contains(annotation.getNameAsString())); + + if (!hasEndpoint) { + return ""; + } + + String classRequestMapping = javaClass.getAnnotations().stream().filter(annotation -> annotation.getNameAsString().equals(RequestMapping.class.getSimpleName())).findFirst() + .map(annotation -> { + if (annotation instanceof SingleMemberAnnotationExpr singleMemberAnnotationExpr) { + return singleMemberAnnotationExpr.getMemberValue().toString(); + } + else if (annotation instanceof NormalAnnotationExpr normalAnnotationExpr) { + return normalAnnotationExpr.getPairs().stream().filter(pair -> "path".equals(pair.getNameAsString())).map(pair -> pair.getValue().toString()).findFirst() + .orElse(""); + } + return ""; + }).orElse(""); + + return classRequestMapping; + } + + /** + * Prints the list of files that failed to parse. + * + * This method checks if the provided list of file paths is not empty. + * If it is not empty, it prints a message indicating that some files failed to parse, + * followed by the paths of the files that failed. + * + * @param filesFailedToParse the list of file paths that failed to parse + */ + private static void printFilesFailedToParse(List filesFailedToParse) { + if (!filesFailedToParse.isEmpty()) { + logger.warn("Files failed to parse:", filesFailedToParse); + for (String file : filesFailedToParse) { + logger.warn(file); + } + } + } + + /** + * Writes the list of endpoint class information to a JSON file. + * + * This method uses the Jackson ObjectMapper to serialize the list of + * EndpointClassInformation objects and write them to a file specified + * by the EndpointParsingResultPath constant. + * + * @param endpointClasses the list of EndpointClassInformation objects to write to the file + */ + private static void writeEndpointsToFile(List endpointClasses) { + try { + new ObjectMapper().writeValue(new File(ENDPOINT_PARSING_RESULT_PATH), endpointClasses); + } + catch (IOException e) { + logger.error("Failed to write endpoint information to file", e); + } + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java new file mode 100644 index 000000000000..57b1d2dfc289 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalysis.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record RestCallAnalysis(List restCallsWithMatchingEndpoints, List restCallsWithoutMatchingEndpoints) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java new file mode 100644 index 000000000000..aac71d6573bf --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallAnalyzer.java @@ -0,0 +1,144 @@ +package de.tum.cit.endpointanalysis; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RestCallAnalyzer { + + private static final String REST_CALL_ANALYSIS_RESULT_PATH = "restCallAnalysisResult.json"; + + private static final Logger logger = LoggerFactory.getLogger(RestCallAnalyzer.class); + + public static void main(String[] args) { + analyzeRestCalls(); + printRestCallAnalysisResult(); + } + + /** + * The RestCallAnalyzer analyzes the client REST Calls and focuses on them having a matching Endpoint on the server + * + * This method reads endpoint and REST call information from JSON files. + * It then matches the REST calls with the endpoints they are calling and + * writes the analysis result to a JSON file. + * REST calls without matching endpoints are also recorded. + */ + private static void analyzeRestCalls() { + ObjectMapper mapper = new ObjectMapper(); + + try { + List endpointClasses = mapper.readValue(new File(EndpointParser.ENDPOINT_PARSING_RESULT_PATH), + new TypeReference>() { + }); + List restCalls = mapper.readValue(new File(EndpointParser.REST_CALL_PARSING_RESULT_PATH), new TypeReference>() { + }); + + List restCallsWithMatchingEndpoint = new ArrayList<>(); + List restCallsWithoutMatchingEndpoint = new ArrayList<>(); + + Map> endpointMap = new HashMap<>(); + + // Populate the map with endpoints + for (EndpointClassInformation endpointClass : endpointClasses) { + for (EndpointInformation endpoint : endpointClass.endpoints()) { + String endpointURI = endpoint.buildComparableEndpointUri(); + endpointMap.computeIfAbsent(endpointURI, uri -> new ArrayList<>()).add(endpoint); + } + } + + for (RestCallFileInformation restCallFile : restCalls) { + for (RestCallInformation restCall : restCallFile.restCalls()) { + String restCallURI = restCall.buildComparableRestCallUri(); + List matchingEndpoints = endpointMap.getOrDefault(restCallURI, new ArrayList<>()); + + checkForWildcardMatches(restCall, matchingEndpoints, restCallURI, endpointMap); + + if (matchingEndpoints.isEmpty()) { + restCallsWithoutMatchingEndpoint.add(restCall); + } + else { + for (EndpointInformation endpoint : matchingEndpoints) { + restCallsWithMatchingEndpoint.add(new RestCallWithMatchingEndpoint(endpoint, restCall, restCall.fileName())); + } + } + } + } + + RestCallAnalysis restCallAnalysis = new RestCallAnalysis(restCallsWithMatchingEndpoint, restCallsWithoutMatchingEndpoint); + mapper.writeValue(new File(REST_CALL_ANALYSIS_RESULT_PATH), restCallAnalysis); + } + catch (IOException e) { + logger.error("Failed to analyze REST calls", e); + } + } + + /** + * Checks for wildcard matches and adds matching endpoints to the list. + * + * This method is used to find matching endpoints for REST calls that use wildcard URIs. + * If no exact match is found for a REST call, it checks if the REST call URI ends with a wildcard ('*'). + * It then iterates through the endpoint map to find URIs that start with the same prefix as the REST call URI + * (excluding the wildcard) and have the same HTTP method. If such URIs are found, they are added to the list of matching endpoints. + * + * @param restCall The REST call information to check for wildcard matches. + * @param matchingEndpoints The list of matching endpoints to be populated. + * @param restCallURI The URI of the REST call being checked. + * @param endpointMap The map of endpoint URIs to their corresponding information. + */ + private static void checkForWildcardMatches(RestCallInformation restCall, List matchingEndpoints, String restCallURI, + Map> endpointMap) { + if (matchingEndpoints.isEmpty() && restCallURI.endsWith("*")) { + for (String uri : endpointMap.keySet()) { + if (uri.startsWith(restCallURI.substring(0, restCallURI.length() - 1)) + && endpointMap.get(uri).get(0).getHttpMethod().toLowerCase().equals(restCall.method().toLowerCase())) { + matchingEndpoints.addAll(endpointMap.get(uri)); + } + } + } + } + + /** + * Prints the endpoint analysis result. + * + * This method reads the endpoint analysis result from a JSON file and prints + * the details of unused endpoints to the console. The details include the + * endpoint URI, HTTP method, file path, and line number. If no matching REST + * call is found for an endpoint, it prints a message indicating this. + */ + private static void printRestCallAnalysisResult() { + ObjectMapper mapper = new ObjectMapper(); + + RestCallAnalysis restCallsAndMatchingEndpoints = null; + + try { + restCallsAndMatchingEndpoints = mapper.readValue(new File(REST_CALL_ANALYSIS_RESULT_PATH), new TypeReference() { + }); + } + catch (IOException e) { + logger.error("Failed to deserialize rest call analysis results", e); + } + + restCallsAndMatchingEndpoints.restCallsWithoutMatchingEndpoints().stream().forEach(endpoint -> { + logger.info("============================================="); + logger.info("REST call URI: {}", endpoint.buildCompleteRestCallURI()); + logger.info("HTTP method: {}", endpoint.method()); + logger.info("File path: {}", endpoint.fileName()); + logger.info("Line: {}", endpoint.line()); + logger.info("============================================="); + logger.info("No matching endpoint found for REST call: {}", endpoint.buildCompleteRestCallURI()); + logger.info("---------------------------------------------"); + logger.info(""); + }); + + logger.info("Number of REST calls without matching endpoints: {}", restCallsAndMatchingEndpoints.restCallsWithoutMatchingEndpoints().size()); + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java new file mode 100644 index 000000000000..847ec03b1561 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallFileInformation.java @@ -0,0 +1,4 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallFileInformation(String fileName, RestCallInformation[] restCalls) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java new file mode 100644 index 000000000000..fb1e44f92f2a --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallInformation.java @@ -0,0 +1,18 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallInformation(String method, String url, int line, String fileName) { + + public String buildCompleteRestCallURI() { + return this.url.replace("`", ""); + } + + public String buildComparableRestCallUri() { + // Replace arguments with placeholder + String result = this.buildCompleteRestCallURI().replaceAll("\\$\\{.*?\\}", ":param:"); + + // Remove query parameters + result = result.split("\\?")[0]; + + return result; + } +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java new file mode 100644 index 000000000000..0b3ebed9d527 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/RestCallWithMatchingEndpoint.java @@ -0,0 +1,4 @@ +package de.tum.cit.endpointanalysis; + +public record RestCallWithMatchingEndpoint(EndpointInformation matchingEndpoint, RestCallInformation restCallInformation, String filePath) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java new file mode 100644 index 000000000000..afdb8fa06846 --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/java/de/tum/cit/endpointanalysis/UsedEndpoints.java @@ -0,0 +1,6 @@ +package de.tum.cit.endpointanalysis; + +import java.util.List; + +public record UsedEndpoints(EndpointInformation endpointInformation, List matchingRestCalls, String filePath) { +} diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts index f774acfdc92b..ad4f19a9322e 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/AnalysisOfEndpointConnectionsClient.ts @@ -1,8 +1,9 @@ -import { readdirSync } from 'node:fs'; +import { readdirSync, readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { Preprocessor } from './Preprocessor'; import { Postprocessor } from './Postprocessor'; import { writeFileSync } from 'node:fs'; +import { parse, TSESTree } from '@typescript-eslint/typescript-estree'; /** * Recursively collects all TypeScript files in a directory. @@ -26,20 +27,58 @@ function collectTypeScriptFiles(dir: string, files: string[] = []) : string[] { return files; } +/** + * Parses a TypeScript file and returns its Abstract Syntax Tree (AST). + * + * @param filePath - The path to the TypeScript file to be parsed. + * @returns The TSESTree of the parsed TypeScript file. + */ +function parseTypeScriptFile(filePath: string): TSESTree.Program | null { + const code = readFileSync(filePath, 'utf8'); + try { + return parse(code, { + loc: true, + comment: true, + tokens: true, + ecmaVersion: 2020, + sourceType: 'module', + }); + } catch (error) { + console.error(`Failed to parse TypeScript file at ${filePath}:`, error); + console.error('Please make sure the file is valid TypeScript code.'); + return null; + } +} + const clientDirPath = resolve('src/main/webapp/app'); const tsFiles = collectTypeScriptFiles(clientDirPath); -// preprocess each file +// create and store Syntax Tree for each file +const astMap = new Map; tsFiles.forEach((filePath) => { - const preProcessor = new Preprocessor(filePath); - preProcessor.preprocessFile(); + const ast = parseTypeScriptFile(filePath); + if (ast) { + astMap.set(filePath, ast); + } +}); + +// preprocess each file +Array.from(astMap.keys()).forEach((filePath: string) => { + const ast = astMap.get(filePath); + if (ast) { + const preProcessor = new Preprocessor(ast); + preProcessor.preprocessFile(); + } }); // postprocess each file -tsFiles.forEach((filePath) => { - const postProcessor = new Postprocessor(filePath); - postProcessor.extractRestCalls(); +Array.from(astMap.keys()).forEach((filePath) => { + const ast = astMap.get(filePath); + if (ast) { + const postProcessor = new Postprocessor(filePath, ast); + postProcessor.extractRestCallsFromProgram(); + } }); try { diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts index b90d216a9796..18b54a5f0ac4 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Postprocessor.ts @@ -38,18 +38,18 @@ class ParsingResult { } export class Postprocessor { - static filesWithRestCalls: { filePath: string, restCalls: RestCall[] }[] = []; + static filesWithRestCalls: { fileName: string, restCalls: RestCall[] }[] = []; private readonly restCalls: RestCall[] = []; - private readonly filePath: string; + private readonly fileName: string; private readonly ast: TSESTree.Program; - constructor(filePath: string) { - this.filePath = filePath; - this.ast = Preprocessor.parseTypeScriptFile(Preprocessor.pathPrefix + filePath) - } - - extractRestCalls() { - this.extractRestCallsFromProgram(); + /** + * @param fileName - The name of the file being processed. + * @param ast - The abstract syntax tree (AST) of the processed file. + */ + constructor(fileName: string, ast: TSESTree.Program) { + this.fileName = fileName; + this.ast = ast; } extractRestCallsFromProgram() { @@ -61,7 +61,7 @@ export class Postprocessor { } }); if (this.restCalls.length > 0) { - Postprocessor.filesWithRestCalls.push( {filePath: this.filePath, restCalls: this.restCalls} ); + Postprocessor.filesWithRestCalls.push( {fileName: this.fileName, restCalls: this.restCalls} ); } } @@ -108,7 +108,7 @@ export class Postprocessor { urlEvaluationResult = this.evaluateUrl(node.arguments[0], methodDefinition, node, classBody); } - const fileName = this.filePath; + const fileName = this.fileName; if (urlEvaluationResult.resultType === ParsingResultType.EVALUATE_URL_SUCCESS) { for (let url of urlEvaluationResult.result) { this.restCalls.push({ method, url, line, fileName }); diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts index a90f30fb7a5e..fcdebd828486 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/Preprocessor.ts @@ -11,16 +11,16 @@ interface SuperClass { interface ChildClass { superClass: string; name: string; - memberVariables: Map; + memberVariables: Map; parentMethodCalls: ParentMethodCalls[]; } interface ParentMethodCalls { name: string; - parameters: MemberVariable[]; + parameters: Attribute[]; } -interface MemberVariable { +interface Attribute { name: string; type: string; value?: string; @@ -28,16 +28,16 @@ interface MemberVariable { export class Preprocessor { public static PREPROCESSING_RESULTS = new Map(); - public static readonly pathPrefix = '' private readonly directoryPrefix = 'src/main/webapp/'; - private readonly fileToPreprocess: string; private ast: TSESTree.Program; - private memberVariables: Map = new Map(); + private memberVariables: Map = new Map(); - constructor(fileToPreprocess: string) { - this.fileToPreprocess = fileToPreprocess; - this.ast = Preprocessor.parseTypeScriptFile(Preprocessor.pathPrefix + this.fileToPreprocess); + /** + * @param ast - The abstract syntax tree (AST) of the processed file. + */ + constructor(ast: TSESTree.Program) { + this.ast = ast; } /** @@ -48,10 +48,6 @@ export class Preprocessor { * It also handles named exports that are class declarations. */ preprocessFile() { - if (this.ast.type !== 'Program') { - return; - } - this.ast.body.forEach((node) => { if (node.type === 'ClassDeclaration') { this.preprocessClass(node); @@ -254,11 +250,11 @@ export class Preprocessor { * which scans the class body for a property matching the parameter name and returns its value. * * @param parameterName - The name of the parameter whose value is to be found. - * @param filePath - The path to the TypeScript file (relative to the base directory set in `pathPrefix` and `directoryPrefix`) where the parameter value is to be searched. + * @param filePath - The path to the TypeScript file (relative to the base directory set in `directoryPrefix`) where the parameter value is to be searched. * @returns The value of the parameter if found; otherwise, an empty string. */ findParameterValueByParameterNameAndFilePath (parameterName: string, filePath: string): string { - const targetAST = Preprocessor.parseTypeScriptFile(`${Preprocessor.pathPrefix}${this.directoryPrefix}${filePath}.ts`); + const targetAST = Preprocessor.parseTypeScriptFile(`${this.directoryPrefix}${filePath}.ts`); for (const node of targetAST.body) { if (node.type === 'ExportNamedDeclaration' && node.declaration?.type === 'ClassDeclaration') { From f4deff34474c3f07e26f3980960e8c1a1da666be Mon Sep 17 00:00:00 2001 From: Florian Glombik <63976129+florian-glombik@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:05:15 +0200 Subject: [PATCH 03/60] Development: Use directive for programming repository button details in exercise detail overview (#9163) --- ...y-repository-buttons-detail.component.html | 25 +++++++++++ ...ary-repository-buttons-detail.component.ts | 20 +++++++++ ...g-repository-buttons-detail.component.html | 8 ++++ ...ing-repository-buttons-detail.component.ts | 16 +++++++ .../detail-overview-list.component.html | 45 ------------------- .../detail-overview-list.component.ts | 5 +-- .../app/detail-overview-list/detail.model.ts | 4 +- .../exercise-detail.directive.ts | 15 ++++++- .../exercise-detail.directive.spec.ts | 25 ++++++++++- 9 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html create mode 100644 src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts diff --git a/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html new file mode 100644 index 000000000000..c22ec3d50039 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.html @@ -0,0 +1,25 @@ +
    + @for (auxiliaryRepository of detail.data.auxiliaryRepositories; track auxiliaryRepository) { + @if (auxiliaryRepository.id && auxiliaryRepository.repositoryUri && detail.data.exerciseId) { +
  • + Repository: {{ auxiliaryRepository.name }} + + +
    + @if (!auxiliaryRepository.checkoutDirectory) { + + + } + + + +
    +
  • + } + } +
diff --git a/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts new file mode 100644 index 000000000000..e44170601ac7 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component.ts @@ -0,0 +1,20 @@ +import { Component, Input } from '@angular/core'; +import { NoDataComponent } from 'app/shared/no-data-component'; +import { RouterModule } from '@angular/router'; +import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; +import { ArtemisProgrammingExerciseActionsModule } from 'app/exercises/programming/shared/actions/programming-exercise-actions.module'; +import { ProgrammingAuxiliaryRepositoryButtonsDetail } from 'app/detail-overview-list/detail.model'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { ArtemisSharedModule } from 'app/shared/shared.module'; + +@Component({ + selector: 'jhi-programming-auxiliary-repository-buttons-detail', + templateUrl: 'programming-auxiliary-repository-buttons-detail.component.html', + standalone: true, + imports: [NoDataComponent, RouterModule, ArtemisSharedComponentModule, ArtemisProgrammingExerciseActionsModule, ArtemisSharedModule], +}) +export class ProgrammingAuxiliaryRepositoryButtonsDetailComponent { + @Input() detail: ProgrammingAuxiliaryRepositoryButtonsDetail; + + readonly faExclamationTriangle = faExclamationTriangle; +} diff --git a/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html new file mode 100644 index 000000000000..95f0a53976b1 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.html @@ -0,0 +1,8 @@ +@if (detail.data.participation?.repositoryUri && detail.data.exerciseId) { +
+ + +
+} @else { + +} diff --git a/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts new file mode 100644 index 000000000000..21676685fed1 --- /dev/null +++ b/src/main/webapp/app/detail-overview-list/components/programming-repository-buttons-detail.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from '@angular/core'; +import type { ProgrammingRepositoryButtonsDetail } from 'app/detail-overview-list/detail.model'; +import { NoDataComponent } from 'app/shared/no-data-component'; +import { RouterModule } from '@angular/router'; +import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; +import { ArtemisProgrammingExerciseActionsModule } from 'app/exercises/programming/shared/actions/programming-exercise-actions.module'; + +@Component({ + selector: 'jhi-programming-repository-buttons-detail', + templateUrl: 'programming-repository-buttons-detail.component.html', + standalone: true, + imports: [NoDataComponent, RouterModule, ArtemisSharedComponentModule, ArtemisProgrammingExerciseActionsModule], +}) +export class ProgrammingRepositoryButtonsDetailComponent { + @Input() detail: ProgrammingRepositoryButtonsDetail; +} diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html index 29ec5888ceae..ae8ce9674c34 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html @@ -15,51 +15,6 @@

{{ section } @switch (detail.type) { - @case (DetailType.ProgrammingRepositoryButtons) { -
- @if (detail.data.participation?.repositoryUri && detail.data.exerciseId) { -
- - -
- } @else { - - } -
- } - @case (DetailType.ProgrammingAuxiliaryRepositoryButtons) { -
-
    - @for (auxiliaryRepository of detail.data.auxiliaryRepositories; track auxiliaryRepository) { - @if (auxiliaryRepository.id && auxiliaryRepository.repositoryUri && detail.data.exerciseId) { -
  • - Repository: {{ auxiliaryRepository.name }} - - -
    - @if (!auxiliaryRepository.checkoutDirectory) { - - - } - - - -
    -
  • - } - } -
-
- } @case (DetailType.ProgrammingTestStatus) {
@if (detail.data.participation) { diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts index b7532ea79cb9..7f98ff940ef1 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { faArrowUpRightFromSquare, faCodeBranch, faCodeCompare, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { faCodeCompare } from '@fortawesome/free-solid-svg-icons'; import { isEmpty } from 'lodash-es'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { ButtonSize, ButtonType, TooltipPlacement } from 'app/shared/components/button.component'; @@ -63,10 +63,7 @@ export class DetailOverviewListComponent implements OnInit, OnDestroy { headlinesRecord: Record; // icons - readonly faExclamationTriangle = faExclamationTriangle; readonly faCodeCompare = faCodeCompare; - readonly faArrowUpRightFromSquare = faArrowUpRightFromSquare; - readonly faCodeBranch = faCodeBranch; WARNING = ButtonType.WARNING; diff --git a/src/main/webapp/app/detail-overview-list/detail.model.ts b/src/main/webapp/app/detail-overview-list/detail.model.ts index 52c7012821aa..f8e8a5562044 100644 --- a/src/main/webapp/app/detail-overview-list/detail.model.ts +++ b/src/main/webapp/app/detail-overview-list/detail.model.ts @@ -83,7 +83,7 @@ interface ProgrammingIrisEnabledDetail extends DetailBase { data: { exercise?: ProgrammingExercise; course?: Course; disabled: boolean; subSettingsType: IrisSubSettingsType }; } -interface ProgrammingRepositoryButtonsDetail extends DetailBase { +export interface ProgrammingRepositoryButtonsDetail extends DetailBase { type: DetailType.ProgrammingRepositoryButtons; data: { exerciseId?: number; @@ -92,7 +92,7 @@ interface ProgrammingRepositoryButtonsDetail extends DetailBase { }; } -interface ProgrammingAuxiliaryRepositoryButtonsDetail extends DetailBase { +export interface ProgrammingAuxiliaryRepositoryButtonsDetail extends DetailBase { type: DetailType.ProgrammingAuxiliaryRepositoryButtons; data: { auxiliaryRepositories: AuxiliaryRepository[]; exerciseId?: number }; } diff --git a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts index 069882e56eb4..9a0cd295b12e 100644 --- a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts +++ b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts @@ -5,6 +5,8 @@ import { TextDetailComponent } from 'app/detail-overview-list/components/text-de import { DateDetailComponent } from 'app/detail-overview-list/components/date-detail.component'; import { LinkDetailComponent } from 'app/detail-overview-list/components/link-detail.component'; import { BooleanDetailComponent } from 'app/detail-overview-list/components/boolean-detail.component'; +import { ProgrammingRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-repository-buttons-detail.component'; +import { ProgrammingAuxiliaryRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component'; @Directive({ selector: '[jhiExerciseDetail]', @@ -23,11 +25,22 @@ export class ExerciseDetailDirective implements OnInit, OnDestroy { } this.detail = this.detail as ShownDetail; - const detailTypeToComponent: { [key in DetailType]?: Type } = { + const detailTypeToComponent: { + [key in DetailType]?: Type< + | TextDetailComponent + | DateDetailComponent + | LinkDetailComponent + | BooleanDetailComponent + | ProgrammingRepositoryButtonsDetailComponent + | ProgrammingAuxiliaryRepositoryButtonsDetailComponent + >; + } = { [DetailType.Text]: TextDetailComponent, [DetailType.Date]: DateDetailComponent, [DetailType.Link]: LinkDetailComponent, [DetailType.Boolean]: BooleanDetailComponent, + [DetailType.ProgrammingRepositoryButtons]: ProgrammingRepositoryButtonsDetailComponent, + [DetailType.ProgrammingAuxiliaryRepositoryButtons]: ProgrammingAuxiliaryRepositoryButtonsDetailComponent, }; const detailComponent = detailTypeToComponent[this.detail.type]; diff --git a/src/test/javascript/spec/component/exercise-detail.directive.spec.ts b/src/test/javascript/spec/component/exercise-detail.directive.spec.ts index 4367413f636f..da435d3b9a84 100644 --- a/src/test/javascript/spec/component/exercise-detail.directive.spec.ts +++ b/src/test/javascript/spec/component/exercise-detail.directive.spec.ts @@ -1,13 +1,25 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ExerciseDetailDirective } from 'app/detail-overview-list/exercise-detail.directive'; import { Component, ViewChild } from '@angular/core'; -import type { BooleanDetail, DateDetail, Detail, LinkDetail, NotShownDetail, ShownDetail, TextDetail } from 'app/detail-overview-list/detail.model'; +import type { + BooleanDetail, + DateDetail, + Detail, + LinkDetail, + NotShownDetail, + ProgrammingAuxiliaryRepositoryButtonsDetail, + ProgrammingRepositoryButtonsDetail, + ShownDetail, + TextDetail, +} from 'app/detail-overview-list/detail.model'; import { TextDetailComponent } from 'app/detail-overview-list/components/text-detail.component'; import { MockComponent } from 'ng-mocks'; import { DetailType } from 'app/detail-overview-list/detail-overview-list.component'; import { DateDetailComponent } from 'app/detail-overview-list/components/date-detail.component'; import { LinkDetailComponent } from 'app/detail-overview-list/components/link-detail.component'; import { BooleanDetailComponent } from 'app/detail-overview-list/components/boolean-detail.component'; +import { ProgrammingRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-repository-buttons-detail.component'; +import { ProgrammingAuxiliaryRepositoryButtonsDetailComponent } from 'app/detail-overview-list/components/programming-auxiliary-repository-buttons-detail.component'; @Component({ template: `
`, @@ -63,6 +75,17 @@ describe('ExerciseDetailDirective', () => { it('should create BooleanDetail component', () => { checkComponentForDetailWasCreated({ type: DetailType.Boolean } as BooleanDetail, BooleanDetailComponent); }); + + it('should create ProgrammingRepositoryButtonsDetailComponent component', () => { + checkComponentForDetailWasCreated({ type: DetailType.ProgrammingRepositoryButtons } as ProgrammingRepositoryButtonsDetail, ProgrammingRepositoryButtonsDetailComponent); + }); + + it('should create ProgrammingAuxiliaryRepositoryButtonsDetailComponent component', () => { + checkComponentForDetailWasCreated( + { type: DetailType.ProgrammingAuxiliaryRepositoryButtons } as ProgrammingAuxiliaryRepositoryButtonsDetail, + ProgrammingAuxiliaryRepositoryButtonsDetailComponent, + ); + }); }); function checkComponentForDetailWasNotCreated(detailToBeChecked: NotShownDetail) { From 0d44cc17c99f62891ab486ded9a6ae68e92abc4a Mon Sep 17 00:00:00 2001 From: Benjamin Schmitz <66966223+bensofficial@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:17:16 +0200 Subject: [PATCH 04/60] Development: Enable http3 for test servers (#9232) --- docker/nginx.yml | 3 ++- docker/nginx/artemis-nginx.conf | 12 ++++++++++-- docker/nginx/artemis-server.conf | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docker/nginx.yml b/docker/nginx.yml index 0baaf14a0629..b7fbc47288cd 100644 --- a/docker/nginx.yml +++ b/docker/nginx.yml @@ -29,7 +29,8 @@ services: hard: 1048576 ports: - "80:80" - - "443:443" + - "443:443/tcp" + - "443:443/udp" # HTTP/3 - "7921:7921" # Git SSH # expose the port to make it reachable docker internally even if the external port mapping changes expose: diff --git a/docker/nginx/artemis-nginx.conf b/docker/nginx/artemis-nginx.conf index fa8f2d0376eb..cbc10836e993 100644 --- a/docker/nginx/artemis-nginx.conf +++ b/docker/nginx/artemis-nginx.conf @@ -18,8 +18,15 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 443 ssl; + listen 443 quic reuseport; + listen [::]:443 ssl; + listen [::]:443 quic reuseport; + http2 on; + http3 on; + http3_hq on; + quic_retry on; + server_name _; ssl_certificate /certs/fullchain.pem; @@ -36,6 +43,7 @@ server { ssl_stapling on; ssl_stapling_verify on; # ssl_early_data on; + quic_gso on; include includes/artemis-server.conf; } diff --git a/docker/nginx/artemis-server.conf b/docker/nginx/artemis-server.conf index a9eb9d592d54..d00af9b9c3dd 100644 --- a/docker/nginx/artemis-server.conf +++ b/docker/nginx/artemis-server.conf @@ -23,6 +23,8 @@ location / { fastcgi_send_timeout 900s; fastcgi_read_timeout 900s; client_max_body_size 128M; + # used to advertise the availability of HTTP/3 + add_header alt-svc 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000'; } location /api/authenticate { From 93e5704fae99f638dfeb10d5b3d4ea8a28a7e1a8 Mon Sep 17 00:00:00 2001 From: Lucas Welscher Date: Wed, 21 Aug 2024 11:18:01 +0200 Subject: [PATCH 05/60] Communication: Fix link in email notification (#9212) --- .../domain/notification/NotificationTargetFactory.java | 6 +++--- .../artemis/notification/NotificationTargetFactoryTest.java | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java b/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java index 86a856dffce2..76f24a8456c4 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/notification/NotificationTargetFactory.java @@ -339,11 +339,11 @@ public static String extractNotificationUrl(Notification notification, String ba * If the post is not associated with a conversation or messaging is disabled in the course, the URL leads to the communication page. * * @param post which information will be needed to create the URL - * @param baseUrl the prefix (depends on current set up (e.g. "http://localhost:9000/courses")) + * @param baseUrl the prefix (depends on current set up (e.g. "http://localhost:9000")) * @return viable URL to the notification related page */ public static String extractNotificationUrl(Post post, String baseUrl) { - // e.g. http://localhost:8080/courses/1/messages?conversationId=123 - return baseUrl + "/courses/" + post.getConversation().getCourse().getId() + "/messages?conversationId=" + post.getConversation().getId(); + // e.g. http://localhost:8080/courses/1/communication?conversationId=123 + return baseUrl + "/courses/" + post.getConversation().getCourse().getId() + "/communication?conversationId=" + post.getConversation().getId(); } } diff --git a/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java b/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java index 96b0db2daa28..c97014991558 100644 --- a/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java +++ b/src/test/java/de/tum/in/www1/artemis/notification/NotificationTargetFactoryTest.java @@ -58,8 +58,6 @@ class NotificationTargetFactoryTest { private static final String BASE_URL = "https://artemistest.ase.in.tum.de"; - private static final String MESSAGES_CONVERSATION = "messages?conversationId="; - private String resultingURL; private static final String PROBLEM_STATEMENT = "problem statement"; @@ -74,8 +72,8 @@ class NotificationTargetFactoryTest { // expected/correct URLs - // e.g. https://artemistest.ase.in.tum.de/courses/477/discussion?searchText=%232000 - private static final String EXPECTED_POST_URL = BASE_URL_COURSES_COURSE_ID + "/" + MESSAGES_CONVERSATION + CHANNEL_ID; + // e.g. https://artemistest.ase.in.tum.de/courses/477/communication?conversationId=2000 + private static final String EXPECTED_POST_URL = BASE_URL_COURSES_COURSE_ID + "/" + "communication?conversationId=" + CHANNEL_ID; // e.g. https://artemistest.ase.in.tum.de/courses/477/lectures/199 private static final String EXPECTED_ATTACHMENT_CHANGED_URL = BASE_URL_COURSES_COURSE_ID + "/" + LECTURES_TEXT + "/" + LECTURE_ID; From cf250f1fe814e033457ef721feb89015cf61b090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Wei=C3=9F?= Date: Wed, 21 Aug 2024 12:19:36 +0200 Subject: [PATCH 06/60] Communication: Fix tooltip translation for the tutor icon in the conversation member list (#9229) --- .../conversation-member-row.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts index 28e03c588910..5044543d4878 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts +++ b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-members/conversation-member-row/conversation-member-row.component.ts @@ -246,7 +246,7 @@ export class ConversationMemberRowComponent implements OnInit, OnDestroy { this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'instructor'); } else if (this.conversationMember.isEditor || this.conversationMember.isTeachingAssistant) { this.userIcon = faUserCheck; - this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'ta'); + this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'tutor'); } else { this.userIcon = faUser; this.userTooltip = this.translateService.instant(toolTipTranslationPath + 'student'); From 360027f0d58a61700e90f7434e273b8e6f0f31ef Mon Sep 17 00:00:00 2001 From: Johannes Wiest Date: Wed, 21 Aug 2024 12:20:33 +0200 Subject: [PATCH 07/60] Lectures: Add bottom padding in course details (#9196) --- .../course-lectures/course-lecture-details.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html b/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html index dc7e8b2eefcf..31e417b42160 100644 --- a/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html +++ b/src/main/webapp/app/overview/course-lectures/course-lecture-details.component.html @@ -36,7 +36,7 @@

-
+
@if (lecture.description) {
@@ -61,8 +61,8 @@

{{ 'artemisApp.courseOverview.lectureDetails.lectureUnits' | artemisTranslat

} @for (lectureUnit of lectureUnits; track lectureUnit) { -
-
+
+
@switch (lectureUnit.type) { @case (LectureUnitType.EXERCISE) { From fc5e849cf01acaa8d54965285c820fa4fa05489c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour <58034472+BBesrour@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:21:18 +0200 Subject: [PATCH 08/60] Programming exercises: Fix import from file not importing build values (#9192) --- .../entities/programming-exercise.model.ts | 4 +- .../programming-exercise-detail.component.ts | 10 +-- .../programming-exercise-update.component.ts | 14 ++-- ...se-custom-aeolus-build-plan.component.html | 6 +- ...cise-custom-aeolus-build-plan.component.ts | 54 +++++++------ ...-exercise-custom-build-plan.component.html | 4 +- ...ng-exercise-custom-build-plan.component.ts | 64 ++++++++------- .../shared/service/aeolus.service.ts | 14 ++-- ...custom-aeolus-build-plan.component.spec.ts | 81 +++++++++++++------ ...ercise-custom-build-plan.component.spec.ts | 67 ++++++++++----- ...gramming-exercise-update.component.spec.ts | 4 +- 11 files changed, 196 insertions(+), 126 deletions(-) diff --git a/src/main/webapp/app/entities/programming-exercise.model.ts b/src/main/webapp/app/entities/programming-exercise.model.ts index 7b72d222cfc4..f8a37efc1b6e 100644 --- a/src/main/webapp/app/entities/programming-exercise.model.ts +++ b/src/main/webapp/app/entities/programming-exercise.model.ts @@ -66,7 +66,7 @@ export class ProgrammingExerciseBuildConfig { public checkoutPath?: string; public timeoutSeconds?: number; public dockerFlags?: string; - public windFile?: WindFile; + public windfile?: WindFile; public testwiseCoverageEnabled?: boolean; constructor() { @@ -176,7 +176,7 @@ export function copyBuildConfigFromExerciseJson(exerciseJson: ProgrammingExercis buildConfig.buildPlanConfiguration = exerciseJson.buildPlanConfiguration ?? ''; buildConfig.checkoutSolutionRepository = exerciseJson.checkoutSolutionRepository ?? false; buildConfig.timeoutSeconds = exerciseJson.timeoutSeconds ?? 0; - buildConfig.windFile = exerciseJson.windFile ?? undefined; + buildConfig.windfile = exerciseJson.windfile ?? undefined; buildConfig.buildScript = exerciseJson.buildScript ?? ''; buildConfig.testwiseCoverageEnabled = exerciseJson.testwiseCoverageEnabled ?? false; buildConfig.dockerFlags = exerciseJson.dockerFlags ?? ''; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts index 55dec97cbd6e..a2f1e2174227 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts @@ -456,13 +456,13 @@ export class ProgrammingExerciseDetailComponent implements OnInit, OnDestroy { }, }, !!exercise.buildConfig?.buildScript && - !!exercise.buildConfig?.windFile?.metadata?.docker?.image && { + !!exercise.buildConfig?.windfile?.metadata?.docker?.image && { type: DetailType.Text, title: 'artemisApp.programmingExercise.dockerImage', - data: { text: exercise.buildConfig?.windFile?.metadata?.docker?.image }, + data: { text: exercise.buildConfig?.windfile?.metadata?.docker?.image }, }, !!exercise.buildConfig?.buildScript && - !!exercise.buildConfig?.windFile?.metadata?.docker?.image && { + !!exercise.buildConfig?.windfile?.metadata?.docker?.image && { type: DetailType.Markdown, title: 'artemisApp.programmingExercise.script', titleHelpText: 'artemisApp.programmingExercise.revertToTemplateBuildPlan', @@ -752,8 +752,8 @@ export class ProgrammingExerciseDetailComponent implements OnInit, OnDestroy { * @param exercise the programming exercise to check */ checkAndSetWindFile(exercise: ProgrammingExercise) { - if (exercise.buildConfig && exercise.buildConfig?.buildPlanConfiguration && !exercise.buildConfig?.windFile) { - exercise.buildConfig!.windFile = this.aeolusService.parseWindFile(exercise.buildConfig?.buildPlanConfiguration); + if (exercise.buildConfig && exercise.buildConfig?.buildPlanConfiguration && !exercise.buildConfig?.windfile) { + exercise.buildConfig!.windfile = this.aeolusService.parseWindFile(exercise.buildConfig?.buildPlanConfiguration); } } diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts index 629b1bc07d26..755a6241cfca 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts @@ -265,7 +265,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest this.withDependenciesValue = false; this.buildPlanLoaded = false; if (this.programmingExercise.buildConfig) { - this.programmingExercise.buildConfig.windFile = undefined; + this.programmingExercise.buildConfig.windfile = undefined; this.programmingExercise.buildConfig.buildPlanConfiguration = undefined; } else { this.programmingExercise.buildConfig = new ProgrammingExerciseBuildConfig(); @@ -390,7 +390,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest this.activatedRoute.data.subscribe(({ programmingExercise }) => { this.programmingExercise = programmingExercise; if (this.programmingExercise.buildConfig?.buildPlanConfiguration) { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig!.buildPlanConfiguration); + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig!.buildPlanConfiguration); } this.backupExercise = cloneDeep(this.programmingExercise); this.selectedProgrammingLanguageValue = this.programmingExercise.programmingLanguage!; @@ -615,15 +615,15 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest */ saveExercise() { // trim potential whitespaces that can lead to issues - if (this.programmingExercise.buildConfig!.windFile?.metadata?.docker?.image) { - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = this.programmingExercise.buildConfig!.windFile.metadata.docker.image.trim(); + if (this.programmingExercise.buildConfig!.windfile?.metadata?.docker?.image) { + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = this.programmingExercise.buildConfig!.windfile.metadata.docker.image.trim(); } - if (this.programmingExercise.customizeBuildPlanWithAeolus) { - this.programmingExercise.buildConfig!.buildPlanConfiguration = this.aeolusService.serializeWindFile(this.programmingExercise.buildConfig!.windFile!); + if (this.programmingExercise.customizeBuildPlanWithAeolus || this.isImportFromFile) { + this.programmingExercise.buildConfig!.buildPlanConfiguration = this.aeolusService.serializeWindFile(this.programmingExercise.buildConfig!.windfile!); } else { this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; } // If the programming exercise has a submission policy with a NONE type, the policy is removed altogether if (this.programmingExercise.submissionPolicy && this.programmingExercise.submissionPolicy.type === SubmissionPolicyType.NONE) { diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html index aa9a31a9dfcf..bcfd1a078ac7 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.html @@ -6,16 +6,16 @@
@if (programmingExercise.customizeBuildPlanWithAeolus) {
- @if (programmingExercise.buildConfig?.windFile && programmingExercise.buildConfig?.windFile?.metadata && programmingExercise.buildConfig?.windFile?.metadata?.docker) { + @if (programmingExercise.buildConfig?.windfile && programmingExercise.buildConfig?.windfile?.metadata && programmingExercise.buildConfig?.windfile?.metadata?.docker) { }
- @for (action of this.programmingExercise.buildConfig?.windFile?.actions; track action) { + @for (action of this.programmingExercise.buildConfig?.windfile?.actions; track action) {

{{ action.name }}

diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts index 92f3a3a31443..4f51ccd37432 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts @@ -42,7 +42,8 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan ngOnChanges(changes: SimpleChanges) { if (changes.programmingExerciseCreationConfig || changes.programmingExercise) { if (this.shouldReloadTemplate()) { - this.loadAeolusTemplate(); + const isImportFromFile = changes.programmingExerciseCreationConfig?.currentValue?.isImportFromFile ?? false; + this.loadAeolusTemplate(isImportFromFile); } } } @@ -62,20 +63,21 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan * @private */ resetCustomBuildPlan() { - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; } /** * Loads the predefined template for the selected programming language and project type * if there is one available. + * @param isImportFromFile whether the exercise is imported from a file * @private */ - loadAeolusTemplate() { - if (this.programmingExercise?.id) { - if (!this.programmingExerciseCreationConfig.buildPlanLoaded && !this.programmingExercise.buildConfig?.windFile) { + loadAeolusTemplate(isImportFromFile: boolean = false) { + if (this.programmingExercise?.id || isImportFromFile) { + if (!this.programmingExerciseCreationConfig.buildPlanLoaded && !this.programmingExercise.buildConfig?.windfile) { if (this.programmingExercise.buildConfig?.buildPlanConfiguration) { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig?.buildPlanConfiguration); + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(this.programmingExercise.buildConfig?.buildPlanConfiguration); } this.programmingExerciseCreationConfig.buildPlanLoaded = true; } @@ -90,16 +92,18 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan this.staticCodeAnalysisEnabled = this.programmingExercise.staticCodeAnalysisEnabled; this.sequentialTestRuns = this.programmingExercise.buildConfig?.sequentialTestRuns; this.testwiseCoverageEnabled = this.programmingExercise.buildConfig?.testwiseCoverageEnabled; - this.aeolusService - .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file) => { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(file); - }, - error: () => { - this.programmingExercise.buildConfig!.windFile = undefined; - }, - }); + if (!isImportFromFile || !this.programmingExercise.buildConfig?.windfile) { + this.aeolusService + .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file) => { + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(file); + }, + error: () => { + this.programmingExercise.buildConfig!.windfile = undefined; + }, + }); + } this.programmingExerciseCreationConfig.buildPlanLoaded = true; } @@ -110,7 +114,7 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan faQuestionCircle = faQuestionCircle; protected getActionScript(action: string): string { - const foundAction: BuildAction | undefined = this.programmingExercise.buildConfig?.windFile?.actions.find((a) => a.name === action); + const foundAction: BuildAction | undefined = this.programmingExercise.buildConfig?.windfile?.actions.find((a) => a.name === action); if (foundAction && foundAction instanceof ScriptAction) { return (foundAction as ScriptAction).script; } @@ -118,12 +122,12 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } changeActiveAction(action: string): void { - if (!this.programmingExercise.buildConfig?.windFile) { + if (!this.programmingExercise.buildConfig?.windfile) { return; } this.code = this.getActionScript(action); - this.active = this.programmingExercise.buildConfig?.windFile.actions.find((a) => a.name === action); + this.active = this.programmingExercise.buildConfig?.windfile.actions.find((a) => a.name === action); this.isScriptAction = this.active instanceof ScriptAction; if (this.isScriptAction && this.editor) { this.editor.setText(this.code); @@ -131,8 +135,8 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } deleteAction(action: string): void { - if (this.programmingExercise.buildConfig?.windFile) { - this.programmingExercise.buildConfig!.windFile.actions = this.programmingExercise.buildConfig?.windFile.actions.filter((a) => a.name !== action); + if (this.programmingExercise.buildConfig?.windfile) { + this.programmingExercise.buildConfig!.windfile.actions = this.programmingExercise.buildConfig?.windfile.actions.filter((a) => a.name !== action); if (this.active?.name === action) { this.active = undefined; this.code = ''; @@ -141,12 +145,12 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } addAction(action: string): void { - if (this.programmingExercise.buildConfig?.windFile) { + if (this.programmingExercise.buildConfig?.windfile) { const newAction = new ScriptAction(); newAction.script = '#!/bin/bash\n\n# Add your custom build plan action here\n\nexit 0'; newAction.name = action; newAction.runAlways = false; - this.programmingExercise.buildConfig?.windFile.actions.push(newAction); + this.programmingExercise.buildConfig?.windfile.actions.push(newAction); this.changeActiveAction(action); } } @@ -194,9 +198,9 @@ export class ProgrammingExerciseCustomAeolusBuildPlanComponent implements OnChan } setDockerImage(dockerImage: string) { - if (!this.programmingExercise.buildConfig?.windFile || !this.programmingExercise.buildConfig?.windFile.metadata.docker) { + if (!this.programmingExercise.buildConfig?.windfile || !this.programmingExercise.buildConfig?.windfile.metadata.docker) { return; } - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = dockerImage.trim(); + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = dockerImage.trim(); } } diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html index 2f05f5d16dd4..0c0e2c702af7 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.html @@ -6,9 +6,9 @@
@if (programmingExercise.customizeBuildPlanWithAeolus) {
- @if (programmingExercise.buildConfig?.windFile && programmingExercise.buildConfig?.windFile?.metadata && programmingExercise.buildConfig?.windFile?.metadata?.docker) { + @if (programmingExercise.buildConfig?.windfile && programmingExercise.buildConfig?.windfile?.metadata && programmingExercise.buildConfig?.windfile?.metadata?.docker) { } diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts index b87916c9c3fd..437d2f56d57e 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts @@ -22,6 +22,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { staticCodeAnalysisEnabled?: boolean; sequentialTestRuns?: boolean; testwiseCoverageEnabled?: boolean; + isImportFromFile: boolean = false; constructor(private aeolusService: AeolusService) {} @@ -32,7 +33,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { this._editor = value; if (this._editor) { this.setupEditor(); - if (this.programmingExercise.id) { + if (this.programmingExercise.id || this.isImportFromFile) { this.code = this.programmingExercise.buildConfig?.buildScript || ''; } this._editor.setText(this.code); @@ -42,7 +43,8 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { ngOnChanges(changes: SimpleChanges) { if (changes.programmingExerciseCreationConfig || changes.programmingExercise) { if (this.shouldReloadTemplate()) { - this.loadAeolusTemplate(); + const isImportFromFile = changes.programmingExerciseCreationConfig?.currentValue?.isImportFromFile ?? false; + this.loadAeolusTemplate(isImportFromFile); } } } @@ -63,7 +65,7 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { * @private */ resetCustomBuildPlan() { - this.programmingExercise.buildConfig!.windFile = undefined; + this.programmingExercise.buildConfig!.windfile = undefined; this.programmingExercise.buildConfig!.buildPlanConfiguration = undefined; this.programmingExercise.buildConfig!.buildScript = undefined; } @@ -71,9 +73,10 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { /** * Loads the predefined template for the selected programming language and project type * if there is one available. + * @param isImportFromFile whether the exercise is imported from a file * @private */ - loadAeolusTemplate() { + loadAeolusTemplate(isImportFromFile: boolean = false) { if (!this.programmingExercise.programmingLanguage) { return; } @@ -82,31 +85,36 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { this.staticCodeAnalysisEnabled = this.programmingExercise.staticCodeAnalysisEnabled; this.sequentialTestRuns = this.programmingExercise.buildConfig?.sequentialTestRuns; this.testwiseCoverageEnabled = this.programmingExercise.buildConfig?.testwiseCoverageEnabled; - this.aeolusService - .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file) => { - this.programmingExercise.buildConfig!.windFile = this.aeolusService.parseWindFile(file); - }, - error: () => { - this.programmingExercise.buildConfig!.windFile = undefined; - }, - }); + this.isImportFromFile = isImportFromFile; + if (!isImportFromFile || !this.programmingExercise.buildConfig?.windfile) { + this.aeolusService + .getAeolusTemplateFile(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file) => { + this.programmingExercise.buildConfig!.windfile = this.aeolusService.parseWindFile(file); + }, + error: () => { + this.programmingExercise.buildConfig!.windfile = undefined; + }, + }); + } this.programmingExerciseCreationConfig.buildPlanLoaded = true; - if (!this.programmingExercise.buildConfig?.windFile) { + if (!this.programmingExercise.buildConfig?.windfile) { this.resetCustomBuildPlan(); } - this.aeolusService - .getAeolusTemplateScript(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) - .subscribe({ - next: (file: string) => { - this.codeChanged(file); - this.editor?.setText(file); - }, - error: () => { - this.programmingExercise.buildConfig!.buildScript = undefined; - }, - }); + if (!isImportFromFile || !this.programmingExercise.buildConfig?.buildScript) { + this.aeolusService + .getAeolusTemplateScript(this.programmingLanguage, this.projectType, this.staticCodeAnalysisEnabled, this.sequentialTestRuns, this.testwiseCoverageEnabled) + .subscribe({ + next: (file: string) => { + this.codeChanged(file); + this.editor?.setText(file); + }, + error: () => { + this.programmingExercise.buildConfig!.buildScript = undefined; + }, + }); + } if (!this.programmingExercise.buildConfig?.buildScript) { this.resetCustomBuildPlan(); } @@ -134,9 +142,9 @@ export class ProgrammingExerciseCustomBuildPlanComponent implements OnChanges { } setDockerImage(dockerImage: string) { - if (!this.programmingExercise.buildConfig?.windFile || !this.programmingExercise.buildConfig?.windFile.metadata.docker) { + if (!this.programmingExercise.buildConfig?.windfile || !this.programmingExercise.buildConfig?.windfile.metadata.docker) { return; } - this.programmingExercise.buildConfig!.windFile.metadata.docker.image = dockerImage.trim(); + this.programmingExercise.buildConfig!.windfile.metadata.docker.image = dockerImage.trim(); } } diff --git a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts index 5871d4ca94f1..e13138c55c04 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts @@ -51,7 +51,7 @@ export class AeolusService { parseWindFile(file: string): WindFile | undefined { try { const templateFile: WindFile = JSON.parse(file); - const windFile: WindFile = Object.assign(new WindFile(), templateFile); + const windfile: WindFile = Object.assign(new WindFile(), templateFile); const actions: BuildAction[] = []; templateFile.actions.forEach((anyAction: any) => { let action: BuildAction | undefined; @@ -71,11 +71,11 @@ export class AeolusService { } }); // somehow, the returned content may have a scriptActions field, which is not a field of the WindFile class - if ('scriptActions' in windFile) { - delete windFile['scriptActions']; + if ('scriptActions' in windfile) { + delete windfile['scriptActions']; } - windFile.actions = actions; - return windFile; + windfile.actions = actions; + return windfile; } catch (SyntaxError) { return undefined; } @@ -100,8 +100,8 @@ export class AeolusService { }; } - serializeWindFile(windFile: WindFile): string { - return JSON.stringify(windFile, this.replacer); + serializeWindFile(windfile: WindFile): string { + return JSON.stringify(windfile, this.replacer); } /** diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts index 93e57264bd42..fdc1d42c64b1 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts @@ -33,7 +33,7 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { const route = { snapshot: { paramMap: convertToParamMap({ courseId: course.id }) } } as any as ActivatedRoute; let programmingExercise = new ProgrammingExercise(course, undefined); - let windFile: WindFile = new WindFile(); + let windfile: WindFile = new WindFile(); let actions: BuildAction[] = []; let gradleBuildAction: ScriptAction = new ScriptAction(); let cleanBuildAction: ScriptAction = new ScriptAction(); @@ -45,11 +45,11 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { beforeEach(() => { programmingExercise = new ProgrammingExercise(course, undefined); programmingExercise.customizeBuildPlanWithAeolus = true; - windFile = new WindFile(); + windfile = new WindFile(); const metadata = new WindMetadata(); metadata.docker = new DockerConfiguration(); metadata.docker.image = 'testImage'; - windFile.metadata = metadata; + windfile.metadata = metadata; actions = []; gradleBuildAction = new ScriptAction(); gradleBuildAction.name = 'gradle'; @@ -65,8 +65,8 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { actions.push(gradleBuildAction); actions.push(cleanBuildAction); actions.push(platformAction); - windFile.actions = actions; - programmingExercise.buildConfig!.windFile = windFile; + windfile.actions = actions; + programmingExercise.buildConfig!.windfile = windfile; TestBed.configureTestingModule({ imports: [ArtemisTestModule], @@ -114,19 +114,19 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { it('should delete action', () => { comp.deleteAction('gradle'); - const size = programmingExercise.buildConfig?.windFile?.actions.length; + const size = programmingExercise.buildConfig?.windfile?.actions.length; expect(size).toBeDefined(); const realSize = size!; - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(realSize); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(realSize); comp.deleteAction('clean'); - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(realSize - 1); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(realSize - 1); }); it('should add action', () => { - const size = programmingExercise.buildConfig?.windFile?.actions.length; + const size = programmingExercise.buildConfig?.windfile?.actions.length; expect(size).toBeDefined(); comp.addAction('gradle clean'); - expect(programmingExercise.buildConfig?.windFile?.actions.length).toBe(size! + 1); + expect(programmingExercise.buildConfig?.windfile?.actions.length).toBe(size! + 1); }); it('should accept editor', () => { @@ -152,7 +152,7 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should do nothing without a Windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; comp.code = 'this should not change'; comp.changeActiveAction(''); expect(comp.code).toBe('this should not change'); @@ -206,12 +206,12 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should reset buildplan', () => { - programmingExercise.buildConfig!.windFile = windFile; + programmingExercise.buildConfig!.windfile = windfile; programmingExercise.buildConfig!.buildPlanConfiguration = 'some build plan'; - expect(programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(programmingExercise.buildConfig?.windfile).toBeDefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeDefined(); comp.resetCustomBuildPlan(); - expect(programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); }); @@ -264,28 +264,28 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should update windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_AEOLUS; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeDefined(); - expect(comp.programmingExercise.buildConfig?.windFile).toEqual(windFile); + expect(comp.programmingExercise.buildConfig?.windfile).toBeDefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toEqual(windfile); }); it('should call this.resetCustomBuildPlan', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_AEOLUS; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; const resetSpy = jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(resetSpy).toHaveBeenCalled(); }); it('should parse windfile correctly', () => { - const parsedWindFile = mockAeolusService.parseWindFile(mockAeolusService.serializeWindFile(windFile)); + const parsedWindFile = mockAeolusService.parseWindFile(mockAeolusService.serializeWindFile(windfile)); expect(parsedWindFile).toBeDefined(); expect(parsedWindFile?.actions.length).toBe(3); expect(parsedWindFile?.actions[0]).toBeInstanceOf(ScriptAction); @@ -341,12 +341,41 @@ describe('ProgrammingExercise Aeolus Custom Build Plan', () => { }); it('should set docker image correctly', () => { - comp.programmingExercise.buildConfig!.windFile = windFile; - comp.programmingExercise.buildConfig!.windFile.metadata.docker.image = 'old'; + comp.programmingExercise.buildConfig!.windfile = windfile; + comp.programmingExercise.buildConfig!.windfile.metadata.docker.image = 'old'; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile?.metadata.docker.image).toBe('testImage'); - comp.programmingExercise.buildConfig!.windFile = undefined; + expect(comp.programmingExercise.buildConfig?.windfile?.metadata.docker.image).toBe('testImage'); + comp.programmingExercise.buildConfig!.windfile = undefined; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); + }); + + it('should not call getAeolusTemplateScript when import from file if script present', () => { + comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + comp.programmingExerciseCreationConfig.isImportFromFile = true; + programmingExercise.buildConfig!.buildScript = 'echo "test"'; + jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); + comp.ngOnChanges({ + programmingExercise: { + currentValue: programmingExercise, + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + programmingExerciseCreationConfig: { + currentValue: JSON.parse(JSON.stringify(comp.programmingExerciseCreationConfig)), + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + }); + expect(mockAeolusService.getAeolusTemplateScript).not.toHaveBeenCalled(); + expect(mockAeolusService.getAeolusTemplateFile).not.toHaveBeenCalled(); + expect(comp.programmingExercise.buildConfig?.buildScript).toBe('echo "test"'); }); }); diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts index 8ce4d5ab6f3c..fe342f5eac56 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts @@ -33,7 +33,7 @@ describe('ProgrammingExercise Custom Build Plan', () => { const route = { snapshot: { paramMap: convertToParamMap({ courseId: course.id }) } } as any as ActivatedRoute; let programmingExercise = new ProgrammingExercise(course, undefined); - let windFile: WindFile = new WindFile(); + let windfile: WindFile = new WindFile(); let actions: BuildAction[] = []; let gradleBuildAction: ScriptAction = new ScriptAction(); let cleanBuildAction: ScriptAction = new ScriptAction(); @@ -45,11 +45,11 @@ describe('ProgrammingExercise Custom Build Plan', () => { beforeEach(() => { programmingExercise = new ProgrammingExercise(course, undefined); programmingExercise.customizeBuildPlanWithAeolus = true; - windFile = new WindFile(); + windfile = new WindFile(); const metadata = new WindMetadata(); metadata.docker = new DockerConfiguration(); metadata.docker.image = 'testImage'; - windFile.metadata = metadata; + windfile.metadata = metadata; actions = []; gradleBuildAction = new ScriptAction(); gradleBuildAction.name = 'gradle'; @@ -63,8 +63,8 @@ describe('ProgrammingExercise Custom Build Plan', () => { actions.push(gradleBuildAction); actions.push(cleanBuildAction); actions.push(platformAction); - windFile.actions = actions; - programmingExercise.buildConfig!.windFile = windFile; + windfile.actions = actions; + programmingExercise.buildConfig!.windfile = windfile; TestBed.configureTestingModule({ imports: [ArtemisTestModule], @@ -127,12 +127,12 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should reset buildplan', () => { - programmingExercise.buildConfig!.windFile = windFile; + programmingExercise.buildConfig!.windfile = windfile; programmingExercise.buildConfig!.buildPlanConfiguration = 'some build plan'; - expect(programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(programmingExercise.buildConfig?.windfile).toBeDefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeDefined(); comp.resetCustomBuildPlan(); - expect(programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); }); @@ -185,23 +185,23 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should update windfile', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_LOCALCI; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.next("echo 'test'"))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeDefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeDefined(); }); it('should call this.resetCustomBuildPlan', () => { - comp.programmingExercise.buildConfig!.windFile = undefined; + comp.programmingExercise.buildConfig!.windfile = undefined; programmingExerciseCreationConfigMock.customBuildPlansSupported = PROFILE_LOCALCI; comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; const resetSpy = jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); comp.loadAeolusTemplate(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); expect(resetSpy).toHaveBeenCalled(); }); @@ -211,7 +211,7 @@ describe('ProgrammingExercise Custom Build Plan', () => { comp.programmingExercise.id = 1; jest.spyOn(comp, 'resetCustomBuildPlan'); jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.next("echo 'test'"))); - jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windFile)))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); comp.loadAeolusTemplate(); expect(comp.resetCustomBuildPlan).not.toHaveBeenCalled(); expect(comp.programmingExercise.buildConfig?.buildScript).toBe("echo 'test'"); @@ -243,12 +243,41 @@ describe('ProgrammingExercise Custom Build Plan', () => { }); it('should set docker image correctly', () => { - comp.programmingExercise.buildConfig!.windFile = windFile; - comp.programmingExercise.buildConfig!.windFile.metadata.docker.image = 'old'; + comp.programmingExercise.buildConfig!.windfile = windfile; + comp.programmingExercise.buildConfig!.windfile.metadata.docker.image = 'old'; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile?.metadata.docker.image).toBe('testImage'); - comp.programmingExercise.buildConfig!.windFile = undefined; + expect(comp.programmingExercise.buildConfig?.windfile?.metadata.docker.image).toBe('testImage'); + comp.programmingExercise.buildConfig!.windfile = undefined; comp.setDockerImage('testImage'); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); + }); + + it('should not call getAeolusTemplateScript when import from file if script present', () => { + comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + comp.programmingExerciseCreationConfig.isImportFromFile = true; + programmingExercise.buildConfig!.buildScript = 'echo "test"'; + jest.spyOn(mockAeolusService, 'getAeolusTemplateScript').mockReturnValue(new Observable((subscriber) => subscriber.error('error'))); + jest.spyOn(mockAeolusService, 'getAeolusTemplateFile').mockReturnValue(new Observable((subscriber) => subscriber.next(mockAeolusService.serializeWindFile(windfile)))); + comp.ngOnChanges({ + programmingExercise: { + currentValue: programmingExercise, + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + programmingExerciseCreationConfig: { + currentValue: JSON.parse(JSON.stringify(comp.programmingExerciseCreationConfig)), + previousValue: undefined, + firstChange: false, + isFirstChange: function (): boolean { + throw new Error('Function not implemented.'); + }, + }, + }); + expect(mockAeolusService.getAeolusTemplateScript).not.toHaveBeenCalled(); + expect(mockAeolusService.getAeolusTemplateFile).not.toHaveBeenCalled(); + expect(comp.programmingExercise.buildConfig?.buildScript).toBe('echo "test"'); }); }); diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts index b5664b00adb5..df1e7b8924b0 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts @@ -438,14 +438,14 @@ describe('ProgrammingExerciseUpdateComponent', () => { // WHEN fixture.detectChanges(); comp.programmingExercise.buildConfig!.buildPlanConfiguration = 'some custom build definition'; - comp.programmingExercise.buildConfig!.windFile = new WindFile(); + comp.programmingExercise.buildConfig!.windfile = new WindFile(); tick(); comp.onProgrammingLanguageChange(ProgrammingLanguage.C); comp.onProjectTypeChange(ProjectType.FACT); // THEN expect(comp.programmingExercise.buildConfig?.buildPlanConfiguration).toBeUndefined(); - expect(comp.programmingExercise.buildConfig?.windFile).toBeUndefined(); + expect(comp.programmingExercise.buildConfig?.windfile).toBeUndefined(); })); }); From b75396d8f0b29b77cdb5efee8df77c7e2ae81ec3 Mon Sep 17 00:00:00 2001 From: Patrik Zander <38403547+pzdr7@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:31:12 +0200 Subject: [PATCH 09/60] Programming exercises: Remove the legacy README.md handling (#9220) --- .../code-editor-file-browser.component.ts | 11 +- ...gramming-exercise-instruction.component.ts | 26 +---- ...code-editor-file-browser.component.spec.ts | 105 ++++++++++++++++- ...ing-exercise-instruction.component.spec.ts | 106 ++---------------- 4 files changed, 116 insertions(+), 132 deletions(-) diff --git a/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts b/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts index 52fa1c7dbd28..16cd6c22176b 100644 --- a/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/code-editor/file-browser/code-editor-file-browser.component.ts @@ -515,8 +515,6 @@ export class CodeEditorFileBrowserComponent implements OnInit, OnChanges, AfterV fromPairs( toPairs(files) .filter(([fileName, fileType]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(fileName, fileType)) - // Filter Readme file that was historically in the student's assignment repo - .filter(([value]) => !value.includes('README.md')) // Filter root folder .filter(([value]) => value), ), @@ -527,14 +525,7 @@ export class CodeEditorFileBrowserComponent implements OnInit, OnChanges, AfterV loadFilesWithInformationAboutChange(): Observable<{ [fileName: string]: boolean }> { return this.repositoryFileService.getFilesWithInformationAboutChange().pipe( - rxMap((files) => - fromPairs( - toPairs(files) - .filter(([filename]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(filename, FileType.FILE)) - // Filter Readme file that was historically in the student's assignment repo - .filter(([value]) => !value.includes('README.md')), - ), - ), + rxMap((files) => fromPairs(toPairs(files).filter(([filename]) => this.allowHiddenFiles || CodeEditorFileBrowserComponent.shouldDisplayFile(filename, FileType.FILE)))), catchError(() => throwError(() => new Error('couldNotBeRetrieved'))), ); } diff --git a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts index 4fd960bbbe2d..75e060446c19 100644 --- a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts @@ -27,7 +27,6 @@ import { TaskArray } from 'app/exercises/programming/shared/instructions-render/ import { Participation } from 'app/entities/participation/participation.model'; import { Feedback } from 'app/entities/feedback.model'; import { ResultService } from 'app/exercises/shared/result/result.service'; -import { RepositoryFileService } from 'app/exercises/shared/result/repository.service'; import { problemStatementHasChanged } from 'app/exercises/shared/exercise/exercise.utils'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { Result } from 'app/entities/result.model'; @@ -51,7 +50,7 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes @Input() public participation: Participation; @Input() generateHtmlEvents: Observable; @Input() personalParticipation: boolean; - // If there are no instructions available (neither in the exercise problemStatement nor the legacy README.md) emits an event + // Emits an event if the instructions are not available via the problemStatement @Output() public onNoInstructionsAvailable = new EventEmitter(); @@ -94,7 +93,6 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes constructor( public viewContainerRef: ViewContainerRef, private resultService: ResultService, - private repositoryFileService: RepositoryFileService, private participationWebsocketService: ParticipationWebsocketService, private programmingExerciseTaskWrapper: ProgrammingExerciseTaskExtensionWrapper, private programmingExercisePlantUmlWrapper: ProgrammingExercisePlantUmlExtensionWrapper, @@ -155,7 +153,7 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes // If the exercise is not loaded, the instructions can't be loaded and so there is no point in loading the results, etc, yet. if (!this.isLoading && this.exercise && this.participation && (this.isInitial || participationHasChanged)) { this.isLoading = true; - return this.loadInstructions().pipe( + return of(this.exercise.problemStatement).pipe( // If no instructions can be loaded, abort pipe and hide the instruction panel tap((problemStatement) => { if (!problemStatement) { @@ -291,26 +289,6 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes ); } - /** - * Loads the instructions for the programming exercise. - * We added the problemStatement later, historically the instructions where a file in the student's repository - * This is why we now prefer the problemStatement and if it doesn't exist try to load the readme. - */ - loadInstructions(): Observable { - if (this.exercise.problemStatement) { - return of(this.exercise.problemStatement); - } else { - if (!this.participation.id) { - return of(undefined); - } - return this.repositoryFileService.get(this.participation.id, 'README.md').pipe( - catchError(() => of(undefined)), - // Old readme files contain chars instead of our domain command tags - replace them when loading the file - map((fileObj) => fileObj && fileObj.fileContent.replace(new RegExp(/✅/, 'g'), '[task]')), - ); - } - } - private renderMarkdown(): void { // Highlight differences between previous and current markdown if ( diff --git a/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts b/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts index 679c1fa41c98..e0916b34a07a 100644 --- a/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts +++ b/src/test/javascript/spec/component/code-editor/code-editor-file-browser.component.spec.ts @@ -19,6 +19,7 @@ import { MockCodeEditorConflictStateService } from '../../helpers/mocks/service/ import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { TreeviewModule } from 'app/exercises/programming/shared/code-editor/treeview/treeview.module'; import { TreeviewItem } from 'app/exercises/programming/shared/code-editor/treeview/models/treeview-item'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; describe('CodeEditorFileBrowserComponent', () => { let comp: CodeEditorFileBrowserComponent; @@ -149,6 +150,25 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renderedFiles).toHaveLength(3); }); + it('should toggle tree compression', () => { + comp.repositoryFiles = { + file1: FileType.FILE, + }; + const treeNode = { + folder: '', + file: 'file1', + children: [], + text: 'file1', + value: 'file1', + }; + jest.spyOn(comp, 'buildTree').mockReturnValue([treeNode]); + const transformTreeToTreeViewItemStub = jest.spyOn(comp, 'transformTreeToTreeViewItem').mockReturnValue([new TreeviewItem(treeNode)]); + comp.compressFolders = false; + comp.toggleTreeCompress(); + expect(comp.compressFolders).toBeTrue(); + expect(transformTreeToTreeViewItemStub).toHaveBeenCalledExactlyOnceWith([treeNode]); + }); + it('should create compressed treeviewItems with nested folder structure', () => { comp.repositoryFiles = { folder: FileType.FOLDER, @@ -205,7 +225,6 @@ describe('CodeEditorFileBrowserComponent', () => { }; const forbiddenFiles = { 'danger.bin': FileType.FILE, - 'README.md': FileType.FILE, '.hidden': FileType.FILE, '.': FileType.FOLDER, }; @@ -310,6 +329,42 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renderedFiles).toHaveLength(0); }); + it('should select the correct file based on the user selection', () => { + const fileToSelect = 'folder/file1'; + const otherFile = 'folder2/file2'; + comp.repositoryFiles = { + folder: FileType.FOLDER, + 'folder/file1': FileType.FILE, + folder2: FileType.FOLDER, + 'folder/file2': FileType.FILE, + }; + comp.filesTreeViewItem = [ + new TreeviewItem({ + checked: false, + text: fileToSelect, + value: fileToSelect, + children: [], + } as any), + new TreeviewItem({ + checked: false, + text: otherFile, + value: otherFile, + children: [], + }), + ]; + comp.selectedFile = undefined; + const nodeFirstFile = comp.filesTreeViewItem[0]; + comp.handleNodeSelected(nodeFirstFile); + expect(nodeFirstFile.checked).toBeTrue(); + expect(comp.selectedFile).toBe(fileToSelect); + // Deselect the current file. + const nodeSecondFile = comp.filesTreeViewItem[1]; + comp.handleNodeSelected(nodeSecondFile); + expect(nodeFirstFile.checked).toBeFalse(); + expect(nodeSecondFile.checked).toBeTrue(); + expect(comp.selectedFile).toBe(otherFile); + }); + it('should set node to checked if its file gets selected and update ui', () => { const selectedFile = 'folder/file1'; const repositoryFiles = { @@ -505,6 +560,26 @@ describe('CodeEditorFileBrowserComponent', () => { expect(createFileStub).not.toHaveBeenCalled(); }); + it('should manage the root file/folder it is currently creating', () => { + comp.setCreatingFileInRoot(FileType.FILE); + expect(comp.creatingFile).toEqual(['', FileType.FILE]); + comp.setCreatingFileInRoot(FileType.FOLDER); + expect(comp.creatingFile).toEqual(['', FileType.FOLDER]); + comp.clearCreatingFile(); + expect(comp.creatingFile).toBeUndefined(); + }); + + it('should manage the file/folder it is currently creating within another folder', () => { + const folder = 'folder'; + const item = { value: folder } as TreeviewItem; + comp.setCreatingFile({ item, fileType: FileType.FILE }); + expect(comp.creatingFile).toEqual([folder, FileType.FILE]); + comp.setCreatingFile({ item, fileType: FileType.FOLDER }); + expect(comp.creatingFile).toEqual([folder, FileType.FOLDER]); + comp.clearCreatingFile(); + expect(comp.creatingFile).toBeUndefined(); + }); + it('should update repository file entry on rename', fakeAsync(() => { const fileName = 'file1'; const afterRename = 'newFileName'; @@ -761,6 +836,18 @@ describe('CodeEditorFileBrowserComponent', () => { expect(renamingInput).toBeNull(); })); + it('should manage the file it is currently renaming', () => { + comp.repositoryFiles = { + 'folder/file1': FileType.FILE, + folder: FileType.FOLDER, + }; + const item = { value: 'folder/file1', text: 'file1' } as TreeviewItem; + comp.setRenamingFile(item); + expect(comp.renamingFile).toEqual(['folder/file1', 'file1', FileType.FILE]); + comp.clearRenamingFile(); + expect(comp.renamingFile).toBeUndefined(); + }); + it('should disable action buttons if there is a git conflict', () => { const repositoryContent: { [fileName: string]: string } = {}; getStatusStub.mockReturnValue(of({ repositoryStatus: CommitState.CONFLICT })); @@ -806,6 +893,7 @@ describe('CodeEditorFileBrowserComponent', () => { const filteredChangeInformation = { 'Class.java': true, 'Document.md': false, + 'README.md': true, }; const getFilesWithChangeInfoStub = jest.fn().mockReturnValue(of(changeInformation)); codeEditorRepositoryFileService.getFilesWithInformationAboutChange = getFilesWithChangeInfoStub; @@ -821,6 +909,21 @@ describe('CodeEditorFileBrowserComponent', () => { loadFiles.unsubscribe(); })); + it('should open a modal when trying to delete a file', () => { + comp.repositoryFiles = { + 'folder/file1': FileType.FILE, + folder: FileType.FOLDER, + }; + const item = { value: 'folder/file1', text: 'file1' } as TreeviewItem; + const modalRef = { componentInstance: { parent: undefined, fileNameToDelete: undefined, fileType: undefined } } as NgbModalRef; + const openModalStub = jest.spyOn(comp.modalService, 'open').mockReturnValue(modalRef); + comp.openDeleteFileModal(item); + expect(openModalStub).toHaveBeenCalledOnce(); + expect(modalRef.componentInstance.parent).toBe(comp); + expect(modalRef.componentInstance.fileNameToDelete).toBe('folder/file1'); + expect(modalRef.componentInstance.fileType).toBe(FileType.FILE); + }); + describe('getFolderBadges', () => { // Mock fileBadges data const mockFileBadges = { diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts index b10b7420640a..4a4bee296170 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts @@ -1,16 +1,15 @@ -import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, flush, tick } from '@angular/core/testing'; import { TranslateService } from '@ngx-translate/core'; import { By } from '@angular/platform-browser'; -import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal, NgbModalRef, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; -import { DebugElement } from '@angular/core'; +import { DebugElement, VERSION } from '@angular/core'; import { Theme, ThemeService } from 'app/core/theme/theme.service'; import dayjs from 'dayjs/esm'; -import { Subject, Subscription, of, throwError } from 'rxjs'; +import { Subscription, of, throwError } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { MockResultService } from '../../helpers/mocks/service/mock-result.service'; -import { MockRepositoryFileService } from '../../helpers/mocks/service/mock-repository-file.service'; import { problemStatementBubbleSortNotExecutedHtml, problemStatementEmptySecondTask, @@ -28,7 +27,6 @@ import { triggerChanges } from '../../helpers/utils/general.utils'; import { LocalStorageService } from 'ngx-webstorage'; import { Participation } from 'app/entities/participation/participation.model'; import { ResultService } from 'app/exercises/shared/result/result.service'; -import { RepositoryFileService } from 'app/exercises/shared/result/repository.service'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { ProgrammingExerciseInstructionTaskStatusComponent } from 'app/exercises/programming/shared/instructions-render/task/programming-exercise-instruction-task-status.component'; import { Result } from 'app/entities/result.model'; @@ -39,25 +37,21 @@ import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.s import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; import { ExerciseType } from 'app/entities/exercise.model'; import { MockTranslateService, TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; -import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { MockModule } from 'ng-mocks'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { SafeHtmlPipe } from 'app/shared/pipes/safe-html.pipe'; -import { VERSION } from '@angular/core'; describe('ProgrammingExerciseInstructionComponent', () => { let comp: ProgrammingExerciseInstructionComponent; let fixture: ComponentFixture; let debugElement: DebugElement; let participationWebsocketService: ParticipationWebsocketService; - let repositoryFileService: RepositoryFileService; let programmingExerciseParticipationService: ProgrammingExerciseParticipationService; let programmingExerciseGradingService: ProgrammingExerciseGradingService; let modalService: NgbModal; let themeService: ThemeService; let subscribeForLatestResultOfParticipationStub: jest.SpyInstance; - let getFileStub: jest.SpyInstance; let openModalStub: jest.SpyInstance; let getLatestResultWithFeedbacks: jest.SpyInstance; @@ -82,7 +76,6 @@ describe('ProgrammingExerciseInstructionComponent', () => { { provide: ResultService, useClass: MockResultService }, { provide: ProgrammingExerciseParticipationService, useClass: MockProgrammingExerciseParticipationService }, { provide: ParticipationWebsocketService, useClass: MockParticipationWebsocketService }, - { provide: RepositoryFileService, useClass: MockRepositoryFileService }, { provide: NgbModal, useClass: MockNgbModalService }, { provide: ProgrammingExerciseGradingService, useValue: { getTestCases: () => of() } }, ], @@ -96,13 +89,11 @@ describe('ProgrammingExerciseInstructionComponent', () => { participationWebsocketService = debugElement.injector.get(ParticipationWebsocketService); programmingExerciseParticipationService = debugElement.injector.get(ProgrammingExerciseParticipationService); programmingExerciseGradingService = debugElement.injector.get(ProgrammingExerciseGradingService); - repositoryFileService = debugElement.injector.get(RepositoryFileService); modalService = debugElement.injector.get(NgbModal); themeService = debugElement.injector.get(ThemeService); subscribeForLatestResultOfParticipationStub = jest.spyOn(participationWebsocketService, 'subscribeForLatestResultOfParticipation'); openModalStub = jest.spyOn(modalService, 'open'); - getFileStub = jest.spyOn(repositoryFileService, 'get'); getLatestResultWithFeedbacks = jest.spyOn(programmingExerciseParticipationService, 'getLatestResultWithFeedback'); comp.personalParticipation = true; @@ -113,13 +104,14 @@ describe('ProgrammingExerciseInstructionComponent', () => { jest.restoreAllMocks(); }); - it('should on participation change clear old subscription for participation results set up new one', () => { + it('should on participation change clear old subscription for participation results set up new one', fakeAsync(() => { const exercise: ProgrammingExercise = { id: 1, numberOfAssessmentsOfCorrectionRounds: [], secondCorrectionEnabled: false, studentAssignedTeamIdComputed: false, isAtLeastTutor: true, + problemStatement: 'lorem ipsum dolor sit amet', }; const oldParticipation: Participation = { id: 1 }; const result: Result = { id: 1 }; @@ -138,84 +130,11 @@ describe('ProgrammingExerciseInstructionComponent', () => { expect(subscribeForLatestResultOfParticipationStub).toHaveBeenCalledOnce(); expect(subscribeForLatestResultOfParticipationStub).toHaveBeenCalledWith(participation.id, true, exercise.id); expect(comp.participationSubscription).not.toEqual(oldSubscription); + flush(); expect(comp.isInitial).toBeTrue(); - }); - - it('should try to fetch README.md from assignment repository if no problemStatement was provided', () => { - const result: Result = { id: 1, feedbacks: [] }; - const participation: Participation = { id: 2 }; - const exercise: ProgrammingExercise = { - id: 3, - course: { id: 4 }, - numberOfAssessmentsOfCorrectionRounds: [], - secondCorrectionEnabled: false, - studentAssignedTeamIdComputed: false, - }; - const getFileSubject = new Subject<{ fileContent: string; fileName: string }>(); - const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); - const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); - getFileStub.mockReturnValue(getFileSubject); - comp.participation = participation; - comp.exercise = exercise; - comp.isInitial = true; - comp.isLoading = false; - - fixture.detectChanges(); - triggerChanges(comp); - fixture.detectChanges(); - expect(comp.isLoading).toBeTrue(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).not.toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).toBeNull(); - expect(getFileStub).toHaveBeenCalledOnce(); - expect(getFileStub).toHaveBeenCalledWith(participation.id, 'README.md'); - - getFileSubject.next({ fileContent: 'lorem ipsum', fileName: 'README.md' }); - expect(comp.problemStatement).toBe('lorem ipsum'); - expect(loadInitialResultStub).toHaveBeenCalledOnce(); - expect(comp.latestResult).toEqual(result); - expect(updateMarkdownStub).toHaveBeenCalledOnce(); - expect(comp.isInitial).toBeFalse(); - expect(comp.isLoading).toBeFalse(); - fixture.detectChanges(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).not.toBeNull(); - }); - - it('should NOT try to fetch README.md from assignment repository if a problemStatement was provided', () => { - const result: Result = { id: 1, feedbacks: [] }; - const participation: Participation = { id: 2 }; - const problemstatement = 'lorem ipsum'; - const exercise: ProgrammingExercise = { - id: 3, - course: { id: 4 }, - problemStatement: problemstatement, - numberOfAssessmentsOfCorrectionRounds: [], - secondCorrectionEnabled: false, - studentAssignedTeamIdComputed: false, - }; - const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); - const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); - comp.participation = participation; - comp.exercise = exercise; - comp.isInitial = true; - comp.isLoading = false; - - fixture.detectChanges(); - triggerChanges(comp); - - expect(getFileStub).not.toHaveBeenCalled(); - expect(comp.problemStatement).toBe('lorem ipsum'); - expect(loadInitialResultStub).toHaveBeenCalledOnce(); - expect(comp.latestResult).toEqual(result); - expect(updateMarkdownStub).toHaveBeenCalledOnce(); - expect(comp.isInitial).toBeFalse(); - expect(comp.isLoading).toBeFalse(); - fixture.detectChanges(); - expect(debugElement.query(By.css('#programming-exercise-instructions-loading'))).toBeNull(); - expect(debugElement.query(By.css('#programming-exercise-instructions-content'))).not.toBeNull(); - }); + })); - it('should emit that no instructions are available if there is neither a problemStatement provided nor a README.md can be retrieved', () => { + it('should emit that no instructions are available if there is no problem statement', () => { const result: Result = { id: 1, feedbacks: [] }; const participation: Participation = { id: 2 }; const exercise: ProgrammingExercise = { @@ -225,11 +144,9 @@ describe('ProgrammingExerciseInstructionComponent', () => { secondCorrectionEnabled: false, studentAssignedTeamIdComputed: false, }; - const getFileSubject = new Subject<{ fileContent: string; fileName: string }>(); const loadInitialResultStub = jest.spyOn(comp, 'loadInitialResult').mockReturnValue(of(result)); const updateMarkdownStub = jest.spyOn(comp, 'updateMarkdown'); const noInstructionsAvailableSpy = jest.spyOn(comp.onNoInstructionsAvailable, 'emit'); - getFileStub.mockReturnValue(getFileSubject); comp.participation = participation; comp.exercise = exercise; comp.isInitial = true; @@ -237,11 +154,6 @@ describe('ProgrammingExerciseInstructionComponent', () => { fixture.detectChanges(); triggerChanges(comp); - expect(comp.isLoading).toBeTrue(); - expect(getFileStub).toHaveBeenCalledOnce(); - expect(getFileStub).toHaveBeenCalledWith(participation.id, 'README.md'); - - getFileSubject.error('fatal error'); expect(comp.problemStatement).toBeUndefined(); expect(loadInitialResultStub).not.toHaveBeenCalled(); expect(comp.latestResult).toBeUndefined(); From 0331b31641159be2eb57cc2b37a57c1e1ac46abb Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Wed, 21 Aug 2024 13:36:11 +0300 Subject: [PATCH 10/60] Development: Update server and client dependencies --- build.gradle | 26 +- gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.properties | 2 +- package-lock.json | 144 ++-- package.json | 16 +- .../build.gradle | 28 +- .../endpoints.json | 1 + .../src/main/typeScript/package-lock.json | 615 ++++++++---------- .../src/main/typeScript/package.json | 11 +- 9 files changed, 404 insertions(+), 446 deletions(-) create mode 100644 supporting_scripts/analysis-of-endpoint-connections/endpoints.json diff --git a/build.gradle b/build.gradle index ae88a8170eda..8eda5b8226e5 100644 --- a/build.gradle +++ b/build.gradle @@ -322,7 +322,7 @@ dependencies { implementation "com.github.docker-java:docker-java-transport-httpclient5:${docker_java_version}" // use newest version of commons-compress to avoid security issues through outdated dependencies - implementation "org.apache.commons:commons-compress:1.27.0" + implementation "org.apache.commons:commons-compress:1.27.1" // import JHipster dependencies BOM @@ -373,8 +373,8 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server:${spring_boot_version}" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:${spring_boot_version}" - implementation "org.springframework.ldap:spring-ldap-core:3.2.4" - implementation "org.springframework.data:spring-data-ldap:3.3.2" + implementation "org.springframework.ldap:spring-ldap-core:3.2.6" + implementation "org.springframework.data:spring-data-ldap:3.3.3" implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:4.1.3") { // NOTE: these modules contain security vulnerabilities and are not needed @@ -385,9 +385,9 @@ dependencies { implementation "org.springframework.cloud:spring-cloud-commons:4.1.4" implementation "io.netty:netty-all:4.1.112.Final" - implementation "io.projectreactor.netty:reactor-netty:1.1.21" - implementation "org.springframework:spring-messaging:6.1.11" - implementation "org.springframework.retry:spring-retry:2.0.7" + implementation "io.projectreactor.netty:reactor-netty:1.1.22" + implementation "org.springframework:spring-messaging:6.1.12" + implementation "org.springframework.retry:spring-retry:2.0.8" implementation "org.springframework.security:spring-security-config:${spring_security_version}" implementation "org.springframework.security:spring-security-data:${spring_security_version}" @@ -427,7 +427,7 @@ dependencies { implementation "org.zalando:jackson-datatype-problem:0.27.1" implementation "com.ibm.icu:icu4j-charset:75.1" implementation "com.github.seancfoley:ipaddress:5.5.0" - implementation "org.apache.maven:maven-model:3.9.8" + implementation "org.apache.maven:maven-model:3.9.9" // NOTE: 3.0.2 is broken for splitting lecture specific PDFs implementation "org.apache.pdfbox:pdfbox:3.0.1" implementation "org.apache.commons:commons-csv:1.11.0" @@ -436,7 +436,7 @@ dependencies { implementation "net.lingala.zip4j:zip4j:2.11.5" implementation "org.jgrapht:jgrapht-core:1.5.2" // use newest version of guava to avoid security issues through outdated dependencies - implementation "com.google.guava:guava:33.2.1-jre" + implementation "com.google.guava:guava:33.3.0-jre" implementation "com.sun.activation:jakarta.activation:2.0.1" // use newest version of gson to avoid security issues through outdated dependencies @@ -470,11 +470,11 @@ dependencies { testImplementation "org.assertj:assertj-core:3.26.3" testImplementation "org.mockito:mockito-core:${mockito_version}" testImplementation "org.mockito:mockito-junit-jupiter:${mockito_version}" - testImplementation "io.github.classgraph:classgraph:4.8.174" + testImplementation "io.github.classgraph:classgraph:4.8.175" testImplementation "org.awaitility:awaitility:4.2.2" testImplementation "org.apache.maven.shared:maven-invoker:3.3.0" - testImplementation "org.gradle:gradle-tooling-api:8.9" - testImplementation "org.apache.maven.surefire:surefire-report-parser:3.3.1" + testImplementation "org.gradle:gradle-tooling-api:8.10" + testImplementation "org.apache.maven.surefire:surefire-report-parser:3.4.0" testImplementation "com.opencsv:opencsv:5.9" testImplementation("io.zonky.test:embedded-database-spring-test:2.5.1") { exclude group: "org.testcontainers", module: "mariadb" @@ -486,7 +486,7 @@ dependencies { } testImplementation("net.bytebuddy:byte-buddy") { version { - strictly "1.14.18" + strictly "1.14.19" } } // cannot update due to "Syntax error in SQL statement "WITH ids_to_delete" @@ -558,7 +558,7 @@ tasks.withType(Test).configureEach { } wrapper { - gradleVersion = "8.9" + gradleVersion = "8.10" } tasks.register("stage") { diff --git a/gradle.properties b/gradle.properties index db7d546da641..cfff6f39ed14 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ npm_version=10.7.0 # Dependency versions jhipster_dependencies_version=8.6.0 spring_boot_version=3.3.2 -spring_security_version=6.3.1 +spring_security_version=6.3.2 # TODO: before we upgrade to 6.5.x, we need to make sure that there are no performance issues with empty sets or lists hibernate_version=6.4.9.Final # TODO: can we update to 5.x? @@ -25,10 +25,11 @@ sshd_version=2.13.2 checkstyle_version=10.17.0 jplag_version=5.1.0 slf4j_version=2.0.16 -sentry_version=7.13.0 +sentry_version=7.14.0 liquibase_version=4.29.1 docker_java_version=3.4.0 -logback_version=1.5.6 +logback_version=1.5.7 +java_parser_version=3.26.1 # gradle plugin version gradle_node_plugin_version=7.0.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5490..9355b4155759 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/package-lock.json b/package-lock.json index 4e2059590f91..bc5fa5d014c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,13 +38,13 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.4", + "ace-builds": "1.35.5", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.38.0", + "core-js": "3.38.1", "crypto-js": "4.2.0", - "dayjs": "1.11.12", + "dayjs": "1.11.13", "diff-match-patch-typescript": "1.0.8", "dompurify": "3.1.6", "export-to-csv": "1.3.0", @@ -61,7 +61,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.4", + "posthog-js": "1.157.2", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -94,14 +94,14 @@ "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.3.0", + "@types/node": "22.4.2", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.1.0", - "@typescript-eslint/parser": "8.1.0", + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", "eslint": "9.9.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", @@ -109,7 +109,7 @@ "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", - "husky": "9.1.4", + "husky": "9.1.5", "jest": "29.7.0", "jest-canvas-mock": "2.5.2", "jest-date-mock": "1.0.10", @@ -6398,13 +6398,13 @@ } }, "node_modules/@types/node": { - "version": "22.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.3.0.tgz", - "integrity": "sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==", + "version": "22.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", + "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.18.2" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -6604,17 +6604,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz", - "integrity": "sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/type-utils": "8.1.0", - "@typescript-eslint/utils": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6638,16 +6638,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.1.0.tgz", - "integrity": "sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { @@ -6667,14 +6667,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz", - "integrity": "sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6685,14 +6685,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz", - "integrity": "sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/utils": "8.1.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6710,9 +6710,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.1.0.tgz", - "integrity": "sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "license": "MIT", "engines": { @@ -6724,14 +6724,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz", - "integrity": "sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6753,16 +6753,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz", - "integrity": "sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6776,13 +6776,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz", - "integrity": "sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -7019,9 +7019,9 @@ } }, "node_modules/ace-builds": { - "version": "1.35.4", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.4.tgz", - "integrity": "sha512-r0KQclhZ/uk5a4zOqRYQkJuQuu4vFMiA6VTj54Tk4nI1TUR3iEMMppZkWbNoWEgWwv4ciDloObb9Rf4V55Qgjw==", + "version": "1.35.5", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.5.tgz", + "integrity": "sha512-yh3V5BLHlN6gwbmk5sV00WRRvdEggJGJ3AIHhOOGHlgDWNWCSvOnHPO7Chb+AqaxxHuvpxOdXd7ZQesaiuJQZQ==", "license": "BSD-3-Clause" }, "node_modules/acorn": { @@ -8643,9 +8643,9 @@ } }, "node_modules/core-js": { - "version": "3.38.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.0.tgz", - "integrity": "sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -9350,9 +9350,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.12", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", - "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "license": "MIT" }, "node_modules/debug": { @@ -11777,9 +11777,9 @@ } }, "node_modules/husky": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", - "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", "dev": true, "license": "MIT", "bin": { @@ -17363,9 +17363,9 @@ "license": "MIT" }, "node_modules/posthog-js": { - "version": "1.155.4", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.155.4.tgz", - "integrity": "sha512-suxwAsmZGqMDXJe/RaCKI3PaDEHiuMDDhKcJklgGAg7eDnywieRkr5CoPcOOvnqTDMnuOPETr98jpYBXKUwGFQ==", + "version": "1.157.2", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.157.2.tgz", + "integrity": "sha512-ATYKGs+Q51u26nHHhrhWNh1whqFm7j/rwQQYw+y6/YzNmRlo+YsqrGZji9nqXb9/4fo0ModDr+ZmuOI3hKkUXA==", "license": "MIT", "dependencies": { "fflate": "^0.4.8", @@ -20089,9 +20089,9 @@ } }, "node_modules/undici-types": { - "version": "6.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", - "integrity": "sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index d48bfbed97b5..1eda30265f5f 100644 --- a/package.json +++ b/package.json @@ -41,13 +41,13 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.4", + "ace-builds": "1.35.5", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.38.0", + "core-js": "3.38.1", "crypto-js": "4.2.0", - "dayjs": "1.11.12", + "dayjs": "1.11.13", "diff-match-patch-typescript": "1.0.8", "dompurify": "3.1.6", "export-to-csv": "1.3.0", @@ -64,7 +64,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.155.4", + "posthog-js": "1.157.2", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -132,14 +132,14 @@ "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.3.0", + "@types/node": "22.4.2", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.1.0", - "@typescript-eslint/parser": "8.1.0", + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", "eslint": "9.9.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", @@ -147,7 +147,7 @@ "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", - "husky": "9.1.4", + "husky": "9.1.5", "jest": "29.7.0", "jest-canvas-mock": "2.5.2", "jest-date-mock": "1.0.10", diff --git a/supporting_scripts/analysis-of-endpoint-connections/build.gradle b/supporting_scripts/analysis-of-endpoint-connections/build.gradle index 0e41c785d65c..226588714dd0 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/build.gradle +++ b/supporting_scripts/analysis-of-endpoint-connections/build.gradle @@ -1,38 +1,38 @@ plugins { - id 'java' - id 'application' + id "java" + id "application" } -group 'de.tum.in.www1.artemis' -version '1.0-SNAPSHOT' +group "de.tum.in.www1.artemis" +version "1.0.0" repositories { mavenCentral() } -evaluationDependsOn(':') +evaluationDependsOn(":") dependencies { - implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.26.0' - implementation 'com.github.javaparser:javaparser-core:3.26.0' - implementation 'com.github.javaparser:javaparser-core-serialization:3.26.0' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' + implementation "com.github.javaparser:javaparser-symbol-solver-core:${project.java_parser_version}" + implementation "com.github.javaparser:javaparser-core:${project.java_parser_version}" + implementation "com.github.javaparser:javaparser-core-serialization:${project.java_parser_version}" + implementation "com.fasterxml.jackson.core:jackson-databind:${project.fasterxml_version}" implementation rootProject.ext.springBootStarterWeb - implementation 'org.slf4j:slf4j-api:1.7.32' - implementation 'ch.qos.logback:logback-classic:1.2.6' + implementation "org.slf4j:slf4j-api:${project.slf4j_version}" + implementation "ch.qos.logback:logback-classic:${project.logback_version}" } task runEndpointParser(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.EndpointParser' + mainClass = "de.tum.cit.endpointanalysis.EndpointParser" } task runEndpointAnalysis(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.EndpointAnalyzer' + mainClass = "de.tum.cit.endpointanalysis.EndpointAnalyzer" } task runRestCallAnalysis(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath - mainClass = 'de.tum.cit.endpointanalysis.RestCallAnalyzer' + mainClass = "de.tum.cit.endpointanalysis.RestCallAnalyzer" } diff --git a/supporting_scripts/analysis-of-endpoint-connections/endpoints.json b/supporting_scripts/analysis-of-endpoint-connections/endpoints.json new file mode 100644 index 000000000000..7846fb272dbc --- /dev/null +++ b/supporting_scripts/analysis-of-endpoint-connections/endpoints.json @@ -0,0 +1 @@ +[{"filePath":"CourseCompetencyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCompetencyTitle","httpMethodAnnotation":"GetMapping","URI":"\"course-competencies/{competencyId}/title\"","className":"CourseCompetencyResource","line":115,"otherAnnotations":["@GetMapping(\"course-competencies/{competencyId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetencyTitles","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/titles\"","className":"CourseCompetencyResource","line":128,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/titles\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}\"","className":"CourseCompetencyResource","line":143,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCompetenciesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies\"","className":"CourseCompetencyResource","line":163,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyStudentProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/student-progress\"","className":"CourseCompetencyResource","line":180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/student-progress\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyCourseProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/course-progress\"","className":"CourseCompetencyResource","line":208,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/course-progress\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetenciesForImport","httpMethodAnnotation":"GetMapping","URI":"\"course-competencies/for-import\"","className":"CourseCompetencyResource","line":226,"otherAnnotations":["@GetMapping(\"course-competencies/for-import\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importAllCompetenciesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/import-all/{sourceCourseId}\"","className":"CourseCompetencyResource","line":242,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyRelations","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/relations\"","className":"CourseCompetencyResource","line":276,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/relations\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetencyRelation","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/relations\"","className":"CourseCompetencyResource","line":294,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/relations\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"removeCompetencyRelation","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/course-competencies/relations/{competencyRelationId}\"","className":"CourseCompetencyResource","line":319,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/course-competencies/relations/{competencyRelationId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateCompetenciesFromCourseDescription","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/course-competencies/generate-from-description\"","className":"CourseCompetencyResource","line":342,"otherAnnotations":["@PostMapping(\"courses/{courseId}/course-competencies/generate-from-description\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"setJudgementOfLearning","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/jol/{jolValue}\"","className":"CourseCompetencyResource","line":364,"otherAnnotations":["@PutMapping(\"courses/{courseId}/course-competencies/{competencyId}/jol/{jolValue}\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLatestJudgementOfLearningForCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/{competencyId}/jol\"","className":"CourseCompetencyResource","line":384,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/{competencyId}/jol\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLatestJudgementOfLearningForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-competencies/jol\"","className":"CourseCompetencyResource","line":403,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-competencies/jol\")","@FeatureToggle(Feature.StudentCourseAnalyticsDashboard)","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"PrerequisiteResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPrerequisitesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":99,"otherAnnotations":["@GetMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getPrerequisite","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/prerequisites/{prerequisiteId}\"","className":"PrerequisiteResource","line":116,"otherAnnotations":["@GetMapping(\"courses/{courseId}/prerequisites/{prerequisiteId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":138,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/bulk\"","className":"PrerequisiteResource","line":160,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/bulk\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importPrerequisite","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import\"","className":"PrerequisiteResource","line":184,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importPrerequisites","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import/bulk\"","className":"PrerequisiteResource","line":211,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import/bulk\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importAllPrerequisitesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import-all/{sourceCourseId}\"","className":"PrerequisiteResource","line":249,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importStandardizedPrerequisites","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/prerequisites/import-standardized\"","className":"PrerequisiteResource","line":283,"otherAnnotations":["@PostMapping(\"courses/{courseId}/prerequisites/import-standardized\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"updatePrerequisite","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/prerequisites\"","className":"PrerequisiteResource","line":302,"otherAnnotations":["@PutMapping(\"courses/{courseId}/prerequisites\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"deletePrerequisite","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/prerequisites/{prerequisiteId}\"","className":"PrerequisiteResource","line":326,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/prerequisites/{prerequisiteId}\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"StandardizedCompetencyResource","classRequestMapping":"\"api/standardized-competencies/\"","endpoints":[{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getStandardizedCompetency","httpMethodAnnotation":"GetMapping","URI":"\"{competencyId}\"","className":"StandardizedCompetencyResource","line":60,"otherAnnotations":["@GetMapping(\"{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getAllForTreeView","httpMethodAnnotation":"GetMapping","URI":"\"for-tree-view\"","className":"StandardizedCompetencyResource","line":76,"otherAnnotations":["@GetMapping(\"for-tree-view\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getKnowledgeArea","httpMethodAnnotation":"GetMapping","URI":"\"knowledge-areas/{knowledgeAreaId}\"","className":"StandardizedCompetencyResource","line":93,"otherAnnotations":["@GetMapping(\"knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/standardized-competencies/\"","endpoint":"getSources","httpMethodAnnotation":"GetMapping","URI":"\"sources\"","className":"StandardizedCompetencyResource","line":109,"otherAnnotations":["@GetMapping(\"sources\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAtLeastInstructor"]}]},{"filePath":"CompetencyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCompetenciesWithProgress","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":96,"otherAnnotations":["@GetMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetency","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/competencies/{competencyId}\"","className":"CompetencyResource","line":113,"otherAnnotations":["@GetMapping(\"courses/{courseId}/competencies/{competencyId}\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetency","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":135,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"createCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/bulk\"","className":"CompetencyResource","line":157,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/bulk\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importCompetency","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import\"","className":"CompetencyResource","line":181,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import/bulk\"","className":"CompetencyResource","line":208,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import/bulk\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importAllCompetenciesFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import-all/{sourceCourseId}\"","className":"CompetencyResource","line":246,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import-all/{sourceCourseId}\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"importStandardizedCompetencies","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/competencies/import-standardized\"","className":"CompetencyResource","line":280,"otherAnnotations":["@PostMapping(\"courses/{courseId}/competencies/import-standardized\")","@EnforceAtLeastEditorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"updateCompetency","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/competencies\"","className":"CompetencyResource","line":299,"otherAnnotations":["@PutMapping(\"courses/{courseId}/competencies\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"deleteCompetency","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/competencies/{competencyId}\"","className":"CompetencyResource","line":323,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/competencies/{competencyId}\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"TextUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTextUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/text-units/{textUnitId}\"","className":"TextUnitResource","line":64,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/text-units/{textUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/text-units\"","className":"TextUnitResource","line":87,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/text-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createTextUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/text-units\"","className":"TextUnitResource","line":119,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/text-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"VideoUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getVideoUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/video-units/{videoUnitId}\"","className":"VideoUnitResource","line":69,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/video-units/{videoUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateVideoUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/video-units\"","className":"VideoUnitResource","line":86,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/video-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createVideoUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/video-units\"","className":"VideoUnitResource","line":115,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/video-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExerciseUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/exercise-units\"","className":"ExerciseUnitResource","line":60,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/exercise-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExerciseUnitsOfLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/exercise-units\"","className":"ExerciseUnitResource","line":90,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/exercise-units\")","@EnforceAtLeastEditor"]}]},{"filePath":"AttachmentUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\"","className":"AttachmentUnitResource","line":99,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateAttachmentUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/attachment-units/{attachmentUnitId}\"","className":"AttachmentUnitResource","line":122,"otherAnnotations":["@PutMapping(value = \"lectures/{lectureId}/attachment-units/{attachmentUnitId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createAttachmentUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units\"","className":"AttachmentUnitResource","line":152,"otherAnnotations":["@PostMapping(value = \"lectures/{lectureId}/attachment-units\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"uploadSlidesForProcessing","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units/upload\"","className":"AttachmentUnitResource","line":188,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/attachment-units/upload\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createAttachmentUnits","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/attachment-units/split/{filename}\"","className":"AttachmentUnitResource","line":217,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/attachment-units/split/{filename}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitsData","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/data/{filename}\"","className":"AttachmentUnitResource","line":247,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/data/{filename}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSlidesToRemove","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachment-units/slides-to-remove/{filename}\"","className":"AttachmentUnitResource","line":275,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachment-units/slides-to-remove/{filename}\")","@EnforceAtLeastEditor"]}]},{"filePath":"OnlineUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOnlineUnit","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/online-units/{onlineUnitId}\"","className":"OnlineUnitResource","line":79,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/online-units/{onlineUnitId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateOnlineUnit","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/online-units\"","className":"OnlineUnitResource","line":96,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/online-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createOnlineUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/online-units\"","className":"OnlineUnitResource","line":126,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/online-units\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getOnlineResource","httpMethodAnnotation":"GetMapping","URI":"\"lectures/online-units/fetch-online-resource\"","className":"OnlineUnitResource","line":161,"otherAnnotations":["@GetMapping(\"lectures/online-units/fetch-online-resource\")","@EnforceAtLeastEditor"]}]},{"filePath":"LectureUnitResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateLectureUnitsOrder","httpMethodAnnotation":"PutMapping","URI":"\"lectures/{lectureId}/lecture-units-order\"","className":"LectureUnitResource","line":85,"otherAnnotations":["@PutMapping(\"lectures/{lectureId}/lecture-units-order\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"completeLectureUnit","httpMethodAnnotation":"PostMapping","URI":"\"lectures/{lectureId}/lecture-units/{lectureUnitId}/completion\"","className":"LectureUnitResource","line":123,"otherAnnotations":["@PostMapping(\"lectures/{lectureId}/lecture-units/{lectureUnitId}/completion\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteLectureUnit","httpMethodAnnotation":"DeleteMapping","URI":"\"lectures/{lectureId}/lecture-units/{lectureUnitId}\"","className":"LectureUnitResource","line":157,"otherAnnotations":["@DeleteMapping(\"lectures/{lectureId}/lecture-units/{lectureUnitId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLectureUnitForLearningPathNodeDetails","httpMethodAnnotation":"GetMapping","URI":"\"lecture-units/{lectureUnitId}/for-learning-path-node-details\"","className":"LectureUnitResource","line":186,"otherAnnotations":["@GetMapping(\"lecture-units/{lectureUnitId}/for-learning-path-node-details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureUnitById","httpMethodAnnotation":"GetMapping","URI":"\"lecture-units/{lectureUnitId}\"","className":"LectureUnitResource","line":201,"otherAnnotations":["@GetMapping(\"lecture-units/{lectureUnitId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"AttachmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAttachment","httpMethodAnnotation":"PostMapping","URI":"\"attachments\"","className":"AttachmentResource","line":88,"otherAnnotations":["@PostMapping(value = \"attachments\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateAttachment","httpMethodAnnotation":"PutMapping","URI":"\"attachments/{attachmentId}\"","className":"AttachmentResource","line":113,"otherAnnotations":["@PutMapping(value = \"attachments/{attachmentId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachment","httpMethodAnnotation":"GetMapping","URI":"\"attachments/{id}\"","className":"AttachmentResource","line":147,"otherAnnotations":["@GetMapping(\"attachments/{id}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentsForLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/attachments\"","className":"AttachmentResource","line":161,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/attachments\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAttachment","httpMethodAnnotation":"DeleteMapping","URI":"\"attachments/{attachmentId}\"","className":"AttachmentResource","line":174,"otherAnnotations":["@DeleteMapping(\"attachments/{attachmentId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"QuizPoolResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateQuizPool","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/quiz-pools\"","className":"QuizPoolResource","line":65,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/quiz-pools\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getQuizPool","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/quiz-pools\"","className":"QuizPoolResource","line":83,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/quiz-pools\")","@EnforceAtLeastInstructor"]}]},{"filePath":"AeolusTemplateResource","classRequestMapping":"\"api/aeolus/\"","endpoints":[{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplate","httpMethodAnnotation":"GetMapping","URI":"\"templates/{language}/{projectType}\"","className":"AeolusTemplateResource","line":67,"otherAnnotations":["@GetMapping({ \"templates/{language}/{projectType}\", \"templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplate","httpMethodAnnotation":"GetMapping","URI":"\"templates/{language}\"","className":"AeolusTemplateResource","line":67,"otherAnnotations":["@GetMapping({ \"templates/{language}/{projectType}\", \"templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplateScript","httpMethodAnnotation":"GetMapping","URI":"\"templateScripts/{language}/{projectType}\"","className":"AeolusTemplateResource","line":94,"otherAnnotations":["@GetMapping({ \"templateScripts/{language}/{projectType}\", \"templateScripts/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/aeolus/\"","endpoint":"getAeolusTemplateScript","httpMethodAnnotation":"GetMapping","URI":"\"templateScripts/{language}\"","className":"AeolusTemplateResource","line":94,"otherAnnotations":["@GetMapping({ \"templateScripts/{language}/{projectType}\", \"templateScripts/{language}\" })","@EnforceAtLeastEditor"]}]},{"filePath":"ConsistencyCheckResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"checkConsistencyOfProgrammingExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{programmingExerciseId}/consistency-check\"","className":"ConsistencyCheckResource","line":52,"otherAnnotations":["@GetMapping(\"programming-exercises/{programmingExerciseId}/consistency-check\")","@EnforceAtLeastEditor"]}]},{"filePath":"PlagiarismPostResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createPost","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/posts\"","className":"PlagiarismPostResource","line":67,"otherAnnotations":["@PostMapping(\"courses/{courseId}/posts\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updatePost","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/posts/{postId}\"","className":"PlagiarismPostResource","line":86,"otherAnnotations":["@PutMapping(\"courses/{courseId}/posts/{postId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPostsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/posts\"","className":"PlagiarismPostResource","line":103,"otherAnnotations":["@GetMapping(\"courses/{courseId}/posts\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deletePost","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/posts/{postId}\"","className":"PlagiarismPostResource","line":127,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/posts/{postId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlagiarismCaseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForCourseForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/for-instructor\"","className":"PlagiarismCaseResource","line":77,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForExamForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/plagiarism-cases/for-instructor\"","className":"PlagiarismCaseResource","line":96,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/plagiarism-cases/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForInstructor","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-instructor\"","className":"PlagiarismCaseResource","line":121,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-instructor\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfPlagiarismCasesForExercise","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/plagiarism-cases-count\"","className":"PlagiarismCaseResource","line":149,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/plagiarism-cases-count\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"savePlagiarismCaseVerdict","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/verdict\"","className":"PlagiarismCaseResource","line":168,"otherAnnotations":["@PutMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/verdict\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForExerciseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/plagiarism-case\"","className":"PlagiarismCaseResource","line":188,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/plagiarism-case\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCasesForExercisesForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases\"","className":"PlagiarismCaseResource","line":206,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismCaseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-student\"","className":"PlagiarismCaseResource","line":254,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-cases/{plagiarismCaseId}/for-student\")","@EnforceAtLeastStudent"]}]},{"filePath":"PlagiarismResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updatePlagiarismComparisonStatus","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/status\"","className":"PlagiarismResource","line":89,"otherAnnotations":["@PutMapping(\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/status\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismComparisonForSplitView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/for-split-view\"","className":"PlagiarismResource","line":122,"otherAnnotations":["@GetMapping(\"courses/{courseId}/plagiarism-comparisons/{comparisonId}/for-split-view\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deletePlagiarismComparisons","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/plagiarism-results/{plagiarismResultId}/plagiarism-comparisons\"","className":"PlagiarismResource","line":185,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/plagiarism-results/{plagiarismResultId}/plagiarism-comparisons\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfPotentialPlagiarismCasesForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/potential-plagiarism-count\"","className":"PlagiarismResource","line":213,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/potential-plagiarism-count\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlagiarismAnswerPostResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAnswerPost","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/answer-posts\"","className":"PlagiarismAnswerPostResource","line":50,"otherAnnotations":["@PostMapping(\"courses/{courseId}/answer-posts\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateAnswerPost","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/answer-posts/{answerPostId}\"","className":"PlagiarismAnswerPostResource","line":69,"otherAnnotations":["@PutMapping(\"courses/{courseId}/answer-posts/{answerPostId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteAnswerPost","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/answer-posts/{answerPostId}\"","className":"PlagiarismAnswerPostResource","line":87,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/answer-posts/{answerPostId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"SubmissionPolicyResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getSubmissionPolicyOfExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":78,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addSubmissionPolicyToProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":104,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeSubmissionPolicyFromProgrammingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":144,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"toggleSubmissionPolicy","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":179,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateSubmissionPolicy","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/submission-policy\"","className":"SubmissionPolicyResource","line":227,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/submission-policy\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationSubmissionCount","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/submission-count\"","className":"SubmissionPolicyResource","line":259,"otherAnnotations":["@GetMapping(\"participations/{participationId}/submission-count\")","@EnforceAtLeastStudent"]}]},{"filePath":"PushNotificationResource","classRequestMapping":"\"api/push_notification/\"","endpoints":[{"requestMapping":"\"api/push_notification/\"","endpoint":"register","httpMethodAnnotation":"PostMapping","URI":"\"register\"","className":"PushNotificationResource","line":78,"otherAnnotations":["@PostMapping(\"register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/push_notification/\"","endpoint":"unregister","httpMethodAnnotation":"DeleteMapping","URI":"\"unregister\"","className":"PushNotificationResource","line":117,"otherAnnotations":["@DeleteMapping(\"unregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"ComplaintResponseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"lockComplaint","httpMethodAnnotation":"PostMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":62,"otherAnnotations":["@PostMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"removeLockFromComplaint","httpMethodAnnotation":"DeleteMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":79,"otherAnnotations":["@DeleteMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"refreshLockOrResolveComplaint","httpMethodAnnotation":"PatchMapping","URI":"\"complaints/{complaintId}/response\"","className":"ComplaintResponseResource","line":96,"otherAnnotations":["@PatchMapping(\"complaints/{complaintId}/response\")","@EnforceAtLeastTutor"]}]},{"filePath":"RepositoryProgrammingExerciseParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getFiles","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files\"","className":"RepositoryProgrammingExerciseParticipationResource","line":186,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/files\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesForPlagiarismView","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-plagiarism-view\"","className":"RepositoryProgrammingExerciseParticipationResource","line":199,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-plagiarism-view\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesAtCommit","httpMethodAnnotation":"GetMapping","URI":"\"repository-files-content/{commitId}\"","className":"RepositoryProgrammingExerciseParticipationResource","line":220,"otherAnnotations":["@GetMapping(value = \"repository-files-content/{commitId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesWithInformationAboutChange","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-change\"","className":"RepositoryProgrammingExerciseParticipationResource","line":240,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-change\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFile","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":254,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileForPlagiarismView","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file-plagiarism-view\"","className":"RepositoryProgrammingExerciseParticipationResource","line":268,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/file-plagiarism-view\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFilesWithContent","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/files-content\"","className":"RepositoryProgrammingExerciseParticipationResource","line":287,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/files-content\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileNames","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/file-names\"","className":"RepositoryProgrammingExerciseParticipationResource","line":303,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/file-names\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createFile","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":315,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createFolder","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/folder\"","className":"RepositoryProgrammingExerciseParticipationResource","line":323,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/folder\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"renameFile","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/rename-file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":331,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/rename-file\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteFile","httpMethodAnnotation":"DeleteMapping","URI":"\"repository/{participationId}/file\"","className":"RepositoryProgrammingExerciseParticipationResource","line":339,"otherAnnotations":["@Override","@DeleteMapping(value = \"repository/{participationId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"pullChanges","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/pull\"","className":"RepositoryProgrammingExerciseParticipationResource","line":346,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}/pull\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipationFiles","httpMethodAnnotation":"PutMapping","URI":"\"repository/{participationId}/files\"","className":"RepositoryProgrammingExerciseParticipationResource","line":361,"otherAnnotations":["@PutMapping(\"repository/{participationId}/files\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"commitChanges","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/commit\"","className":"RepositoryProgrammingExerciseParticipationResource","line":406,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/commit\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"resetToLastCommit","httpMethodAnnotation":"PostMapping","URI":"\"repository/{participationId}/reset\"","className":"RepositoryProgrammingExerciseParticipationResource","line":414,"otherAnnotations":["@Override","@PostMapping(value = \"repository/{participationId}/reset\", produces = MediaType.APPLICATION_JSON_VALUE)","@FeatureToggle(Feature.ProgrammingExercises)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}\"","className":"RepositoryProgrammingExerciseParticipationResource","line":422,"otherAnnotations":["@Override","@GetMapping(value = \"repository/{participationId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getBuildLogs","httpMethodAnnotation":"GetMapping","URI":"\"repository/{participationId}/buildlogs\"","className":"RepositoryProgrammingExerciseParticipationResource","line":438,"otherAnnotations":["@GetMapping(value = \"repository/{participationId}/buildlogs\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastStudent"]}]},{"filePath":"TestRepositoryResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getFiles","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/files\"","className":"TestRepositoryResource","line":99,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/files\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFile","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":106,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createFile","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":113,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"createFolder","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/folder\"","className":"TestRepositoryResource","line":121,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/folder\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"renameFile","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/rename-file\"","className":"TestRepositoryResource","line":129,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/rename-file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"deleteFile","httpMethodAnnotation":"DeleteMapping","URI":"\"test-repository/{exerciseId}/file\"","className":"TestRepositoryResource","line":137,"otherAnnotations":["@Override","@DeleteMapping(value = \"test-repository/{exerciseId}/file\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"pullChanges","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}/pull\"","className":"TestRepositoryResource","line":145,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}/pull\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"commitChanges","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/commit\"","className":"TestRepositoryResource","line":152,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/commit\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"resetToLastCommit","httpMethodAnnotation":"PostMapping","URI":"\"test-repository/{exerciseId}/reset\"","className":"TestRepositoryResource","line":160,"otherAnnotations":["@Override","@PostMapping(value = \"test-repository/{exerciseId}/reset\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"test-repository/{exerciseId}\"","className":"TestRepositoryResource","line":168,"otherAnnotations":["@Override","@GetMapping(value = \"test-repository/{exerciseId}\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTestFiles","httpMethodAnnotation":"PutMapping","URI":"\"test-repository/{exerciseId}/files\"","className":"TestRepositoryResource","line":184,"otherAnnotations":["@PutMapping(\"test-repository/{exerciseId}/files\")","@EnforceAtLeastTutor"]}]},{"filePath":"NotificationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllNotificationsForCurrentUserFilteredBySettings","httpMethodAnnotation":"GetMapping","URI":"\"notifications\"","className":"NotificationResource","line":74,"otherAnnotations":["@GetMapping(\"notifications\")","@EnforceAtLeastStudent"]}]},{"filePath":"FileResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveMarkdownFile","httpMethodAnnotation":"PostMapping","URI":"\"markdown-file-upload\"","className":"FileResource","line":151,"otherAnnotations":["@PostMapping(\"markdown-file-upload\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getMarkdownFile","httpMethodAnnotation":"GetMapping","URI":"\"files/markdown/{filename}\"","className":"FileResource","line":170,"otherAnnotations":["@GetMapping(\"files/markdown/{filename}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateFile","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/{language}/{projectType}\"","className":"FileResource","line":188,"otherAnnotations":["@GetMapping({ \"files/templates/{language}/{projectType}\", \"files/templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateFile","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/{language}\"","className":"FileResource","line":188,"otherAnnotations":["@GetMapping({ \"files/templates/{language}/{projectType}\", \"files/templates/{language}\" })","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getDragAndDropBackgroundFile","httpMethodAnnotation":"GetMapping","URI":"\"files/drag-and-drop/backgrounds/{questionId}/*\"","className":"FileResource","line":224,"otherAnnotations":["@GetMapping(\"files/drag-and-drop/backgrounds/{questionId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getDragItemFile","httpMethodAnnotation":"GetMapping","URI":"\"files/drag-and-drop/drag-items/{dragItemId}/*\"","className":"FileResource","line":240,"otherAnnotations":["@GetMapping(\"files/drag-and-drop/drag-items/{dragItemId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmission","httpMethodAnnotation":"GetMapping","URI":"\"files/file-upload-exercises/{exerciseId}/submissions/{submissionId}/*\"","className":"FileResource","line":260,"otherAnnotations":["@GetMapping(\"files/file-upload-exercises/{exerciseId}/submissions/{submissionId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseIcon","httpMethodAnnotation":"GetMapping","URI":"\"files/course/icons/{courseId}/*\"","className":"FileResource","line":293,"otherAnnotations":["@GetMapping(\"files/course/icons/{courseId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseCodeOfConduct","httpMethodAnnotation":"GetMapping","URI":"\"files/templates/code-of-conduct\"","className":"FileResource","line":307,"otherAnnotations":["@GetMapping(\"files/templates/code-of-conduct\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getUserSignature","httpMethodAnnotation":"GetMapping","URI":"\"files/exam-user/signatures/{examUserId}/*\"","className":"FileResource","line":322,"otherAnnotations":["@GetMapping(\"files/exam-user/signatures/{examUserId}/*\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExamUserImage","httpMethodAnnotation":"GetMapping","URI":"\"files/exam-user/{examUserId}/*\"","className":"FileResource","line":338,"otherAnnotations":["@GetMapping(\"files/exam-user/{examUserId}/*\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLectureAttachment","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/lecture/{lectureId}/{filename}\"","className":"FileResource","line":355,"otherAnnotations":["@GetMapping(\"files/attachments/lecture/{lectureId}/{filename}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLecturePdfAttachmentsMerged","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/lecture/{lectureId}/merge-pdf\"","className":"FileResource","line":383,"otherAnnotations":["@GetMapping(\"files/attachments/lecture/{lectureId}/merge-pdf\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitAttachment","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/attachment-unit/{attachmentUnitId}/*\"","className":"FileResource","line":415,"otherAnnotations":["@GetMapping(\"files/attachments/attachment-unit/{attachmentUnitId}/*\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAttachmentUnitAttachmentSlide","httpMethodAnnotation":"GetMapping","URI":"\"files/attachments/attachment-unit/{attachmentUnitId}/slide/{slideNumber}\"","className":"FileResource","line":438,"otherAnnotations":["@GetMapping(\"files/attachments/attachment-unit/{attachmentUnitId}/slide/{slideNumber}\")","@EnforceAtLeastStudent"]}]},{"filePath":"AndroidAppSiteAssociationResource","classRequestMapping":"\".well-known/\"","endpoints":[{"requestMapping":"\".well-known/\"","endpoint":"getAndroidAssetLinks","httpMethodAnnotation":"GetMapping","URI":"\"assetlinks.json\"","className":"AndroidAppSiteAssociationResource","line":40,"otherAnnotations":["@GetMapping(\"assetlinks.json\")","@ManualConfig"]}]},{"filePath":"LinkPreviewResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLinkPreview","httpMethodAnnotation":"PostMapping","URI":"\"link-preview\"","className":"LinkPreviewResource","line":40,"otherAnnotations":["@PostMapping(\"link-preview\")","@EnforceAtLeastStudent","@Cacheable(value = \"linkPreview\", key = \"#url\", unless = \"#result == null\")"]}]},{"filePath":"AccountResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveAccount","httpMethodAnnotation":"PutMapping","URI":"\"account\"","className":"AccountResource","line":60,"otherAnnotations":["@PutMapping(\"account\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"changePassword","httpMethodAnnotation":"PostMapping","URI":"\"account/change-password\"","className":"AccountResource","line":85,"otherAnnotations":["@PostMapping(\"account/change-password\")","@EnforceAtLeastStudent"]}]},{"filePath":"AthenaResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTextFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/text-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":160,"otherAnnotations":["@GetMapping(\"athena/text-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/programming-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":174,"otherAnnotations":["@GetMapping(\"athena/programming-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingFeedbackSuggestions","httpMethodAnnotation":"GetMapping","URI":"\"athena/modeling-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\"","className":"AthenaResource","line":188,"otherAnnotations":["@GetMapping(\"athena/modeling-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForTextExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/text-exercises/available-modules\"","className":"AthenaResource","line":201,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/text-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForProgrammingExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/programming-exercises/available-modules\"","className":"AthenaResource","line":213,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/programming-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableModulesForModelingExercises","httpMethodAnnotation":"GetMapping","URI":"\"athena/courses/{courseId}/modeling-exercises/available-modules\"","className":"AthenaResource","line":225,"otherAnnotations":["@GetMapping(\"athena/courses/{courseId}/modeling-exercises/available-modules\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/submissions/{submissionId}/repository\"","className":"AthenaResource","line":251,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/submissions/{submissionId}/repository\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getTemplateRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/template\"","className":"AthenaResource","line":267,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/template\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/solution\"","className":"AthenaResource","line":283,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/solution\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"getTestRepository","httpMethodAnnotation":"GetMapping","URI":"\"public/athena/programming-exercises/{exerciseId}/repository/tests\"","className":"AthenaResource","line":299,"otherAnnotations":["@GetMapping(\"public/athena/programming-exercises/{exerciseId}/repository/tests\")","// We check the Athena secret instead\n@EnforceNothing","@ManualConfig"]}]},{"filePath":"TutorialGroupSessionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfTutorialGroup","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":102,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":125,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"updateAttendanceCount","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/attendance-count\"","className":"TutorialGroupSessionResource","line":171,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/attendance-count\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"deleteSession","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\"","className":"TutorialGroupSessionResource","line":193,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions\"","className":"TutorialGroupSessionResource","line":213,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"cancel","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/cancel\"","className":"TutorialGroupSessionResource","line":256,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/cancel\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"activate","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/activate\"","className":"TutorialGroupSessionResource","line":284,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/sessions/{sessionId}/activate\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupFreePeriodResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfConfiguration","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":74,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":97,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods\"","className":"TutorialGroupFreePeriodResource","line":145,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"delete","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\"","className":"TutorialGroupFreePeriodResource","line":190,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}/tutorial-free-periods/{tutorialGroupFreePeriodId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTitle","httpMethodAnnotation":"GetMapping","URI":"\"tutorial-groups/{tutorialGroupId}/title\"","className":"TutorialGroupResource","line":132,"otherAnnotations":["@GetMapping(\"tutorial-groups/{tutorialGroupId}/title\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getUniqueCampusValues","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/campus-values\"","className":"TutorialGroupResource","line":148,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/campus-values\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getUniqueLanguageValues","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/language-values\"","className":"TutorialGroupResource","line":166,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/language-values\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getAllForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups\"","className":"TutorialGroupResource","line":183,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"getOneOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":203,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups\"","className":"TutorialGroupResource","line":222,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"delete","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":283,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\"","className":"TutorialGroupResource","line":318,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"deregisterStudent","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/deregister/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"TutorialGroupResource","line":406,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/deregister/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"registerStudent","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"TutorialGroupResource","line":428,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"registerMultipleStudentsToTutorialGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register-multiple\"","className":"TutorialGroupResource","line":455,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/{tutorialGroupId}/register-multiple\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"importRegistrations","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups/import\"","className":"TutorialGroupResource","line":477,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups/import\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"exportTutorialGroupsToCSV","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/export/csv\"","className":"TutorialGroupResource","line":550,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/tutorial-groups/export/csv\", produces = \"text/csv\")","@EnforceAtLeastInstructorInCourse","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"exportTutorialGroupsToJSON","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups/export/json\"","className":"TutorialGroupResource","line":581,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/tutorial-groups/export/json\", produces = MediaType.APPLICATION_JSON_VALUE)","@EnforceAtLeastInstructorInCourse","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"TutorialGroupsConfigurationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getOneOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration\"","className":"TutorialGroupsConfigurationResource","line":69,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutorial-groups-configuration\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"create","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration\"","className":"TutorialGroupsConfigurationResource","line":86,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutorial-groups-configuration\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]},{"requestMapping":"\"api/\"","endpoint":"update","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}\"","className":"TutorialGroupsConfigurationResource","line":121,"otherAnnotations":["@PutMapping(\"courses/{courseId}/tutorial-groups-configuration/{tutorialGroupsConfigurationId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.TutorialGroups)"]}]},{"filePath":"BonusResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBonusForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus\"","className":"BonusResource","line":95,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/bonus\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"calculateGradeWithBonus","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/calculate-raw\"","className":"BonusResource","line":134,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/bonus/calculate-raw\")","@EnforceAdmin","// TODO: Remove the manual configuration once the endpoint gets it's final pre-authorization when the feature releases.\n@ManualConfig"]},{"requestMapping":"\"api/\"","endpoint":"createBonusForExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus\"","className":"BonusResource","line":163,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/bonus\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateBonus","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\"","className":"BonusResource","line":228,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteBonus","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\"","className":"BonusResource","line":282,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/bonus/{bonusId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ApollonConversionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"convertApollonModel","httpMethodAnnotation":"PostMapping","URI":"\"apollon/convert-to-pdf\"","className":"ApollonConversionResource","line":42,"otherAnnotations":["@PostMapping(\"apollon/convert-to-pdf\")","@EnforceAtLeastStudent"]}]},{"filePath":"IrisModelsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllModels","httpMethodAnnotation":"GetMapping","URI":"\"iris/models\"","className":"IrisModelsResource","line":36,"otherAnnotations":["@GetMapping(\"iris/models\")","@EnforceAtLeastEditor"]}]},{"filePath":"IrisResource","classRequestMapping":"\"api/iris/\"","endpoints":[{"requestMapping":"\"api/iris/\"","endpoint":"getStatus","httpMethodAnnotation":"GetMapping","URI":"\"status\"","className":"IrisResource","line":37,"otherAnnotations":["@GetMapping(\"status\")","@EnforceAtLeastStudent"]}]},{"filePath":"IrisExerciseChatSessionResource","classRequestMapping":"\"api/iris/exercise-chat/\"","endpoints":[{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"getCurrentSessionOrCreateIfNotExists","httpMethodAnnotation":"PostMapping","URI":"\"{exerciseId}/sessions/current\"","className":"IrisExerciseChatSessionResource","line":70,"otherAnnotations":["@PostMapping(\"{exerciseId}/sessions/current\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"getAllSessions","httpMethodAnnotation":"GetMapping","URI":"\"{exerciseId}/sessions\"","className":"IrisExerciseChatSessionResource","line":96,"otherAnnotations":["@GetMapping(\"{exerciseId}/sessions\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/iris/exercise-chat/\"","endpoint":"createSessionForExercise","httpMethodAnnotation":"PostMapping","URI":"\"{exerciseId}/sessions\"","className":"IrisExerciseChatSessionResource","line":118,"otherAnnotations":["@PostMapping(\"{exerciseId}/sessions\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"IrisCourseChatSessionResource","classRequestMapping":"\"api/iris/course-chat/\"","endpoints":[{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"getCurrentSessionOrCreateIfNotExists","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/sessions/current\"","className":"IrisCourseChatSessionResource","line":70,"otherAnnotations":["@PostMapping(\"{courseId}/sessions/current\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"getAllSessions","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/sessions\"","className":"IrisCourseChatSessionResource","line":87,"otherAnnotations":["@GetMapping(\"{courseId}/sessions\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/iris/course-chat/\"","endpoint":"createSessionForCourse","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/sessions\"","className":"IrisCourseChatSessionResource","line":109,"otherAnnotations":["@PostMapping(\"{courseId}/sessions\")","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"IrisSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGlobalSettings","httpMethodAnnotation":"GetMapping","URI":"\"iris/global-iris-settings\"","className":"IrisSettingsResource","line":58,"otherAnnotations":["@GetMapping(\"iris/global-iris-settings\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getRawCourseSettings","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":71,"otherAnnotations":["@GetMapping(\"courses/{courseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getRawProgrammingExerciseSettings","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":86,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseSettings","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/iris-settings\"","className":"IrisSettingsResource","line":103,"otherAnnotations":["@GetMapping(\"courses/{courseId}/iris-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseSettings","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/iris-settings\"","className":"IrisSettingsResource","line":122,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/iris-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateCourseSettings","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":140,"otherAnnotations":["@PutMapping(\"courses/{courseId}/raw-iris-settings\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExerciseSettings","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/raw-iris-settings\"","className":"IrisSettingsResource","line":158,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/raw-iris-settings\")","@EnforceAtLeastInstructor"]}]},{"filePath":"IrisMessageResource","classRequestMapping":"\"api/iris/\"","endpoints":[{"requestMapping":"\"api/iris/\"","endpoint":"getMessages","httpMethodAnnotation":"GetMapping","URI":"\"sessions/{sessionId}/messages\"","className":"IrisMessageResource","line":65,"otherAnnotations":["@GetMapping(\"sessions/{sessionId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"createMessage","httpMethodAnnotation":"PostMapping","URI":"\"sessions/{sessionId}/messages\"","className":"IrisMessageResource","line":83,"otherAnnotations":["@PostMapping(\"sessions/{sessionId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"resendMessage","httpMethodAnnotation":"PostMapping","URI":"\"sessions/{sessionId}/messages/{messageId}/resend\"","className":"IrisMessageResource","line":110,"otherAnnotations":["@PostMapping(\"sessions/{sessionId}/messages/{messageId}/resend\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/iris/\"","endpoint":"rateMessage","httpMethodAnnotation":"PutMapping","URI":"\"sessions/{sessionId}/messages/{messageId}/helpful\"","className":"IrisMessageResource","line":140,"otherAnnotations":["@PutMapping(value = \"sessions/{sessionId}/messages/{messageId}/helpful\")","@EnforceAtLeastStudent"]}]},{"filePath":"TextSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTextSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":107,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateTextSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":127,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTextSubmissionWithResults","httpMethodAnnotation":"GetMapping","URI":"\"text-submissions/{submissionId}\"","className":"TextSubmissionResource","line":164,"otherAnnotations":["@GetMapping(\"text-submissions/{submissionId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllTextSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/text-submissions\"","className":"TextSubmissionResource","line":190,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/text-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTextSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/text-submission-without-assessment\"","className":"TextSubmissionResource","line":208,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/text-submission-without-assessment\")","@EnforceAtLeastTutor"]}]},{"filePath":"SubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"deleteSubmission","httpMethodAnnotation":"DeleteMapping","URI":"\"submissions/{submissionId}\"","className":"SubmissionResource","line":105,"otherAnnotations":["@DeleteMapping(\"submissions/{submissionId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getTestRunSubmissionsForAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/test-run-submissions\"","className":"SubmissionResource","line":141,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/test-run-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsWithComplaintsForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions-with-complaints\"","className":"SubmissionResource","line":179,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions-with-complaints\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsWithMoreFeedbackRequestForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/more-feedback-requests-with-complaints\"","className":"SubmissionResource","line":200,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/more-feedback-requests-with-complaints\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsOnPageWithSize","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions-for-import\"","className":"SubmissionResource","line":219,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions-for-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionVersions","httpMethodAnnotation":"GetMapping","URI":"\"submissions/{submissionId}/versions\"","className":"SubmissionResource","line":258,"otherAnnotations":["@GetMapping(\"submissions/{submissionId}/versions\")","@EnforceAtLeastInstructor"]}]},{"filePath":"LtiResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"lti13DeepLinking","httpMethodAnnotation":"PostMapping","URI":"\"lti13/deep-linking/{courseId}\"","className":"LtiResource","line":84,"otherAnnotations":["@PostMapping(\"lti13/deep-linking/{courseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllConfiguredLtiPlatforms","httpMethodAnnotation":"GetMapping","URI":"\"lti-platforms\"","className":"LtiResource","line":112,"otherAnnotations":["@GetMapping(\"lti-platforms\")","@EnforceAtLeastInstructor"]}]},{"filePath":"QuizSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveOrSubmitForLiveMode","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/live\"","className":"QuizSubmissionResource","line":100,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/live\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitForPractice","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/practice\"","className":"QuizSubmissionResource","line":125,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/practice\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitForPreview","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/submissions/preview\"","className":"QuizSubmissionResource","line":188,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/submissions/preview\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"submitQuizForExam","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/submissions/exam\"","className":"QuizSubmissionResource","line":226,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/submissions/exam\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"StatisticsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getChartData","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/data-for-content\"","className":"StatisticsResource","line":63,"otherAnnotations":["@GetMapping(\"management/statistics/data-for-content\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseStatistics","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/course-statistics\"","className":"StatisticsResource","line":84,"otherAnnotations":["@GetMapping(\"management/statistics/course-statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStatistics","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/exercise-statistics\"","className":"StatisticsResource","line":98,"otherAnnotations":["@GetMapping(\"management/statistics/exercise-statistics\")","@EnforceAtLeastTutor"]}]},{"filePath":"ConversationMessageResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createMessage","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/messages\"","className":"ConversationMessageResource","line":80,"otherAnnotations":["@PostMapping(\"courses/{courseId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getMessages","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/messages\"","className":"ConversationMessageResource","line":111,"otherAnnotations":["@GetMapping(\"courses/{courseId}/messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateMessage","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/messages/{messageId}\"","className":"ConversationMessageResource","line":161,"otherAnnotations":["@PutMapping(\"courses/{courseId}/messages/{messageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteMessage","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/messages/{messageId}\"","className":"ConversationMessageResource","line":179,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/messages/{messageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateDisplayPriority","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/messages/{postId}/display-priority\"","className":"ConversationMessageResource","line":199,"otherAnnotations":["@PutMapping(\"courses/{courseId}/messages/{postId}/display-priority\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"computeSimilarityScoresWitCoursePosts","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/messages/similarity-check\"","className":"ConversationMessageResource","line":213,"otherAnnotations":["@PostMapping(\"courses/{courseId}/messages/similarity-check\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllPostTagsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/messages/tags\"","className":"ConversationMessageResource","line":228,"otherAnnotations":["@GetMapping(\"courses/{courseId}/messages/tags\")","// TODO: unused, delete\n@EnforceAtLeastStudent"]}]},{"filePath":"AnswerMessageResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createAnswerMessage","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/answer-messages\"","className":"AnswerMessageResource","line":47,"otherAnnotations":["@PostMapping(\"courses/{courseId}/answer-messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateAnswerMessage","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/answer-messages/{answerMessageId}\"","className":"AnswerMessageResource","line":67,"otherAnnotations":["@PutMapping(\"courses/{courseId}/answer-messages/{answerMessageId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteAnswerMessage","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/answer-messages/{answerMessageId}\"","className":"AnswerMessageResource","line":85,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/answer-messages/{answerMessageId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ReactionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createReaction","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/postings/reactions\"","className":"ReactionResource","line":50,"otherAnnotations":["@PostMapping(\"courses/{courseId}/postings/reactions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteReaction","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/postings/reactions/{reactionId}\"","className":"ReactionResource","line":72,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/postings/reactions/{reactionId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ConversationResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"getConversationsOfUser","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/conversations\"","className":"ConversationResource","line":82,"otherAnnotations":["@GetMapping(\"{courseId}/conversations\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsFavorite","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/favorite\"","className":"ConversationResource","line":102,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/favorite\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsHidden","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/hidden\"","className":"ConversationResource","line":120,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/hidden\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateIsMuted","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/conversations/{conversationId}/muted\"","className":"ConversationResource","line":138,"otherAnnotations":["@PostMapping(\"{courseId}/conversations/{conversationId}/muted\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"hasUnreadMessages","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/unread-messages\"","className":"ConversationResource","line":154,"otherAnnotations":["@GetMapping(\"{courseId}/unread-messages\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"markAsRead","httpMethodAnnotation":"PatchMapping","URI":"\"{courseId}/conversations/{conversationId}/mark-as-read\"","className":"ConversationResource","line":171,"otherAnnotations":["@PatchMapping(\"{courseId}/conversations/{conversationId}/mark-as-read\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"isCodeOfConductAccepted","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/code-of-conduct/agreement\"","className":"ConversationResource","line":190,"otherAnnotations":["@GetMapping(\"{courseId}/code-of-conduct/agreement\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"acceptCodeOfConduct","httpMethodAnnotation":"PatchMapping","URI":"\"{courseId}/code-of-conduct/agreement\"","className":"ConversationResource","line":206,"otherAnnotations":["@PatchMapping(\"{courseId}/code-of-conduct/agreement\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getResponsibleUsersForCodeOfConduct","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/code-of-conduct/responsible-users\"","className":"ConversationResource","line":223,"otherAnnotations":["@GetMapping(\"{courseId}/code-of-conduct/responsible-users\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"searchMembersOfConversation","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/conversations/{conversationId}/members/search\"","className":"ConversationResource","line":249,"otherAnnotations":["@GetMapping(\"{courseId}/conversations/{conversationId}/members/search\")","@EnforceAtLeastStudent"]}]},{"filePath":"OneToOneChatResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"startOneToOneChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/one-to-one-chats\"","className":"OneToOneChatResource","line":71,"otherAnnotations":["@PostMapping(\"{courseId}/one-to-one-chats\")","@EnforceAtLeastStudent"]}]},{"filePath":"ChannelResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"getCourseChannelsOverview","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/channels/overview\"","className":"ChannelResource","line":106,"otherAnnotations":["@GetMapping(\"{courseId}/channels/overview\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getCoursePublicChannelsOverview","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/channels/public-overview\"","className":"ChannelResource","line":135,"otherAnnotations":["@GetMapping(\"{courseId}/channels/public-overview\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getExerciseChannel","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/exercises/{exerciseId}/channel\"","className":"ChannelResource","line":161,"otherAnnotations":["@GetMapping(\"{courseId}/exercises/{exerciseId}/channel\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"getLectureChannel","httpMethodAnnotation":"GetMapping","URI":"\"{courseId}/lectures/{lectureId}/channel\"","className":"ChannelResource","line":186,"otherAnnotations":["@GetMapping(\"{courseId}/lectures/{lectureId}/channel\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"createChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels\"","className":"ChannelResource","line":212,"otherAnnotations":["@PostMapping(\"{courseId}/channels\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateChannel","httpMethodAnnotation":"PutMapping","URI":"\"{courseId}/channels/{channelId}\"","className":"ChannelResource","line":244,"otherAnnotations":["@PutMapping(\"{courseId}/channels/{channelId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deleteChannel","httpMethodAnnotation":"DeleteMapping","URI":"\"{courseId}/channels/{channelId}\"","className":"ChannelResource","line":272,"otherAnnotations":["@DeleteMapping(\"{courseId}/channels/{channelId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"archiveChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/archive\"","className":"ChannelResource","line":303,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/archive\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"unArchiveChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/unarchive\"","className":"ChannelResource","line":322,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/unarchive\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"grantChannelModeratorRole","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/grant-channel-moderator\"","className":"ChannelResource","line":342,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/grant-channel-moderator\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"revokeChannelModeratorRole","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/revoke-channel-moderator\"","className":"ChannelResource","line":365,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/revoke-channel-moderator\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"registerUsersToChannel","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/register\"","className":"ChannelResource","line":395,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deregisterUsers","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/channels/{channelId}/deregister\"","className":"ChannelResource","line":433,"otherAnnotations":["@PostMapping(\"{courseId}/channels/{channelId}/deregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"GroupChatResource","classRequestMapping":"\"api/courses/\"","endpoints":[{"requestMapping":"\"api/courses/\"","endpoint":"startGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats\"","className":"GroupChatResource","line":80,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"updateGroupChat","httpMethodAnnotation":"PutMapping","URI":"\"{courseId}/group-chats/{groupChatId}\"","className":"GroupChatResource","line":115,"otherAnnotations":["@PutMapping(\"{courseId}/group-chats/{groupChatId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"registerUsersToGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats/{groupChatId}/register\"","className":"GroupChatResource","line":139,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats/{groupChatId}/register\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/courses/\"","endpoint":"deregisterUsersFromGroupChat","httpMethodAnnotation":"PostMapping","URI":"\"{courseId}/group-chats/{groupChatId}/deregister\"","className":"GroupChatResource","line":167,"otherAnnotations":["@PostMapping(\"{courseId}/group-chats/{groupChatId}/deregister\")","@EnforceAtLeastStudent"]}]},{"filePath":"ModelingSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createModelingSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":108,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":128,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllModelingSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/modeling-submissions\"","className":"ModelingSubmissionResource","line":171,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = GET_200_SUBMISSIONS_REASON, response = ModelingSubmission.class, responseContainer = \"List\"), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@GetMapping(\"exercises/{exerciseId}/modeling-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"modeling-submissions/{submissionId}\"","className":"ModelingSubmissionResource","line":195,"otherAnnotations":["@GetMapping(\"modeling-submissions/{submissionId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getModelingSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/modeling-submission-without-assessment\"","className":"ModelingSubmissionResource","line":258,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/modeling-submission-without-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestSubmissionForModelingEditor","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/latest-modeling-submission\"","className":"ModelingSubmissionResource","line":300,"otherAnnotations":["@GetMapping(\"participations/{participationId}/latest-modeling-submission\")","@EnforceAtLeastStudent"]}]},{"filePath":"GradingScaleResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGradingScaleForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":85,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradingScaleForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":102,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllGradingScalesInInstructorGroupOnPage","httpMethodAnnotation":"GetMapping","URI":"\"grading-scales\"","className":"GradingScaleResource","line":120,"otherAnnotations":["@GetMapping(\"grading-scales\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createGradingScaleForCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":135,"otherAnnotations":["@PostMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createGradingScaleForExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":173,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateGradingScaleForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":201,"otherAnnotations":["@PutMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateGradingScaleForExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":226,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteGradingScaleForCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/grading-scale\"","className":"GradingScaleResource","line":251,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/grading-scale\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteGradingScaleForExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale\"","className":"GradingScaleResource","line":269,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/grading-scale\")","@EnforceAtLeastInstructor"]}]},{"filePath":"UserResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"searchAllUsers","httpMethodAnnotation":"GetMapping","URI":"\"users/search\"","className":"UserResource","line":96,"otherAnnotations":["@GetMapping(\"users/search\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateUserNotificationDate","httpMethodAnnotation":"PutMapping","URI":"\"users/notification-date\"","className":"UserResource","line":120,"otherAnnotations":["@PutMapping(\"users/notification-date\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateUserNotificationVisibility","httpMethodAnnotation":"PutMapping","URI":"\"users/notification-visibility\"","className":"UserResource","line":135,"otherAnnotations":["@PutMapping(\"users/notification-visibility\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"initializeUser","httpMethodAnnotation":"PutMapping","URI":"\"users/initialize\"","className":"UserResource","line":151,"otherAnnotations":["@PutMapping(\"users/initialize\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"setIrisAcceptedToTimestamp","httpMethodAnnotation":"PutMapping","URI":"\"users/accept-iris\"","className":"UserResource","line":173,"otherAnnotations":["@PutMapping(\"users/accept-iris\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addSshPublicKey","httpMethodAnnotation":"PutMapping","URI":"\"users/sshpublickey\"","className":"UserResource","line":191,"otherAnnotations":["@PutMapping(\"users/sshpublickey\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteSshPublicKey","httpMethodAnnotation":"DeleteMapping","URI":"\"users/sshpublickey\"","className":"UserResource","line":218,"otherAnnotations":["@DeleteMapping(\"users/sshpublickey\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getVcsAccessToken","httpMethodAnnotation":"GetMapping","URI":"\"users/vcsToken\"","className":"UserResource","line":236,"otherAnnotations":["@GetMapping(\"users/vcsToken\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createVcsAccessToken","httpMethodAnnotation":"PutMapping","URI":"\"users/vcsToken\"","className":"UserResource","line":252,"otherAnnotations":["@PutMapping(\"users/vcsToken\")","@EnforceAtLeastStudent"]}]},{"filePath":"LearningPathResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"enableLearningPathsForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/learning-paths/enable\"","className":"LearningPathResource","line":108,"otherAnnotations":["@PutMapping(\"courses/{courseId}/learning-paths/enable\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateMissingLearningPathsForCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/learning-paths/generate-missing\"","className":"LearningPathResource","line":129,"otherAnnotations":["@PutMapping(\"courses/{courseId}/learning-paths/generate-missing\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathsOnPage","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-paths\"","className":"LearningPathResource","line":147,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-paths\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getHealthStatusForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-path-health\"","className":"LearningPathResource","line":162,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-path-health\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}\"","className":"LearningPathResource","line":177,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathCompetencyGraph","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competency-graph\"","className":"LearningPathResource","line":196,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competency-graph\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNgxGraph","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/graph\"","className":"LearningPathResource","line":215,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/graph\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNgxPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/path\"","className":"LearningPathResource","line":229,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/path\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getRelativeLearningPathNavigation","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/relative-navigation\"","className":"LearningPathResource","line":246,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/relative-navigation\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNavigation","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/navigation\"","className":"LearningPathResource","line":265,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/navigation\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathNavigationOverview","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/navigation-overview\"","className":"LearningPathResource","line":281,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/navigation-overview\")","@FeatureToggle(Feature.LearningPaths)","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningPathId","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/learning-path-id\"","className":"LearningPathResource","line":309,"otherAnnotations":["@GetMapping(\"courses/{courseId}/learning-path-id\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"generateLearningPath","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/learning-path\"","className":"LearningPathResource","line":325,"otherAnnotations":["@PostMapping(\"courses/{courseId}/learning-path\")","@EnforceAtLeastStudentInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyProgressForLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competency-progress\"","className":"LearningPathResource","line":349,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competency-progress\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCompetencyOrderForLearningPath","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competencies\"","className":"LearningPathResource","line":371,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competencies\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLearningObjectsForCompetency","httpMethodAnnotation":"GetMapping","URI":"\"learning-path/{learningPathId}/competencies/{competencyId}/learning-objects\"","className":"LearningPathResource","line":393,"otherAnnotations":["@GetMapping(\"learning-path/{learningPathId}/competencies/{competencyId}/learning-objects\")","@EnforceAtLeastStudent"]}]},{"filePath":"ScienceSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getScienceSettingsForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"science-settings\"","className":"ScienceSettingsResource","line":61,"otherAnnotations":["@GetMapping(\"science-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveScienceSettingsForCurrentUser","httpMethodAnnotation":"PutMapping","URI":"\"science-settings\"","className":"ScienceSettingsResource","line":79,"otherAnnotations":["@PutMapping(\"science-settings\")","@EnforceAtLeastStudent"]}]},{"filePath":"ScienceResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"science","httpMethodAnnotation":"PutMapping","URI":"\"science\"","className":"ScienceResource","line":42,"otherAnnotations":["@PutMapping(value = \"science\")","@FeatureToggle(Feature.Science)","@EnforceAtLeastStudent"]}]},{"filePath":"AdminSystemNotificationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createSystemNotification","httpMethodAnnotation":"PostMapping","URI":"\"system-notifications\"","className":"AdminSystemNotificationResource","line":60,"otherAnnotations":["@PostMapping(\"system-notifications\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateSystemNotification","httpMethodAnnotation":"PutMapping","URI":"\"system-notifications\"","className":"AdminSystemNotificationResource","line":81,"otherAnnotations":["@PutMapping(\"system-notifications\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteSystemNotification","httpMethodAnnotation":"DeleteMapping","URI":"\"system-notifications/{notificationId}\"","className":"AdminSystemNotificationResource","line":103,"otherAnnotations":["@DeleteMapping(\"system-notifications/{notificationId}\")","@EnforceAdmin"]}]},{"filePath":"AdminTextAssessmentEventResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getEventsByCourseId","httpMethodAnnotation":"GetMapping","URI":"\"event-insights/text-assessment/events/{courseId}\"","className":"AdminTextAssessmentEventResource","line":38,"otherAnnotations":["@GetMapping(\"event-insights/text-assessment/events/{courseId}\")","@EnforceAdmin"]}]},{"filePath":"AdminDataExportResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"requestDataExportForUser","httpMethodAnnotation":"PostMapping","URI":"\"data-exports/{login}\"","className":"AdminDataExportResource","line":36,"otherAnnotations":["@PostMapping(\"data-exports/{login}\")","@EnforceAdmin"]}]},{"filePath":"AdminExamResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getCurrentAndUpcomingExams","httpMethodAnnotation":"GetMapping","URI":"\"courses/upcoming-exams\"","className":"AdminExamResource","line":40,"otherAnnotations":["@GetMapping(\"courses/upcoming-exams\")","@EnforceAdmin"]}]},{"filePath":"AdminIrisSettingsResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"updateGlobalSettings","httpMethodAnnotation":"PutMapping","URI":"\"iris/global-iris-settings\"","className":"AdminIrisSettingsResource","line":34,"otherAnnotations":["@PutMapping(\"iris/global-iris-settings\")","@EnforceAdmin"]}]},{"filePath":"AdminBuildJobQueueResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getQueuedBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"queued-jobs\"","className":"AdminBuildJobQueueResource","line":56,"otherAnnotations":["@GetMapping(\"queued-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getRunningBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"running-jobs\"","className":"AdminBuildJobQueueResource","line":69,"otherAnnotations":["@GetMapping(\"running-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildAgentSummary","httpMethodAnnotation":"GetMapping","URI":"\"build-agents\"","className":"AdminBuildJobQueueResource","line":82,"otherAnnotations":["@GetMapping(\"build-agents\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildAgentDetails","httpMethodAnnotation":"GetMapping","URI":"\"build-agent\"","className":"AdminBuildJobQueueResource","line":96,"otherAnnotations":["@GetMapping(\"build-agent\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelBuildJob","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-job/{buildJobId}\"","className":"AdminBuildJobQueueResource","line":111,"otherAnnotations":["@DeleteMapping(\"cancel-job/{buildJobId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllQueuedBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-queued-jobs\"","className":"AdminBuildJobQueueResource","line":126,"otherAnnotations":["@DeleteMapping(\"cancel-all-queued-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllRunningBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-running-jobs\"","className":"AdminBuildJobQueueResource","line":141,"otherAnnotations":["@DeleteMapping(\"cancel-all-running-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"cancelAllRunningBuildJobsForAgent","httpMethodAnnotation":"DeleteMapping","URI":"\"cancel-all-running-jobs-for-agent\"","className":"AdminBuildJobQueueResource","line":157,"otherAnnotations":["@DeleteMapping(\"cancel-all-running-jobs-for-agent\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getFinishedBuildJobs","httpMethodAnnotation":"GetMapping","URI":"\"finished-jobs\"","className":"AdminBuildJobQueueResource","line":173,"otherAnnotations":["@GetMapping(\"finished-jobs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getBuildJobStatistics","httpMethodAnnotation":"GetMapping","URI":"\"build-job-statistics\"","className":"AdminBuildJobQueueResource","line":192,"otherAnnotations":["@GetMapping(\"build-job-statistics\")","@EnforceAdmin"]}]},{"filePath":"AdminStandardizedCompetencyResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createStandardizedCompetency","httpMethodAnnotation":"PostMapping","URI":"\"standardized-competencies\"","className":"AdminStandardizedCompetencyResource","line":63,"otherAnnotations":["@PostMapping(\"standardized-competencies\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateStandardizedCompetency","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/{competencyId}\"","className":"AdminStandardizedCompetencyResource","line":81,"otherAnnotations":["@PutMapping(\"standardized-competencies/{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteStandardizedCompetency","httpMethodAnnotation":"DeleteMapping","URI":"\"standardized-competencies/{competencyId}\"","className":"AdminStandardizedCompetencyResource","line":99,"otherAnnotations":["@DeleteMapping(\"standardized-competencies/{competencyId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"createKnowledgeArea","httpMethodAnnotation":"PostMapping","URI":"\"standardized-competencies/knowledge-areas\"","className":"AdminStandardizedCompetencyResource","line":117,"otherAnnotations":["@PostMapping(\"standardized-competencies/knowledge-areas\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateKnowledgeArea","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\"","className":"AdminStandardizedCompetencyResource","line":136,"otherAnnotations":["@PutMapping(\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteKnowledgeArea","httpMethodAnnotation":"DeleteMapping","URI":"\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\"","className":"AdminStandardizedCompetencyResource","line":153,"otherAnnotations":["@DeleteMapping(\"standardized-competencies/knowledge-areas/{knowledgeAreaId}\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"importStandardizedCompetencyCatalog","httpMethodAnnotation":"PutMapping","URI":"\"standardized-competencies/import\"","className":"AdminStandardizedCompetencyResource","line":170,"otherAnnotations":["@PutMapping(\"standardized-competencies/import\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"exportStandardizedCompetencyCatalog","httpMethodAnnotation":"GetMapping","URI":"\"standardized-competencies/export\"","className":"AdminStandardizedCompetencyResource","line":186,"otherAnnotations":["@GetMapping(\"standardized-competencies/export\")","@FeatureToggle(Feature.StandardizedCompetencies)","@EnforceAdmin"]}]},{"filePath":"AdminCourseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getAllGroupsForAllCourses","httpMethodAnnotation":"GetMapping","URI":"\"courses/groups\"","className":"AdminCourseResource","line":92,"otherAnnotations":["@GetMapping(\"courses/groups\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"createCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses\"","className":"AdminCourseResource","line":115,"otherAnnotations":["@PostMapping(value = \"courses\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}\"","className":"AdminCourseResource","line":169,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}\")","@EnforceAdmin"]}]},{"filePath":"AdminStatisticsResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getChartData","httpMethodAnnotation":"GetMapping","URI":"\"management/statistics/data\"","className":"AdminStatisticsResource","line":46,"otherAnnotations":["@GetMapping(\"management/statistics/data\")","@EnforceAdmin"]}]},{"filePath":"AdminExerciseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getUpcomingExercises","httpMethodAnnotation":"GetMapping","URI":"\"exercises/upcoming\"","className":"AdminExerciseResource","line":40,"otherAnnotations":["@GetMapping(\"exercises/upcoming\")","@EnforceAdmin"]}]},{"filePath":"AdminUserResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"createUser","httpMethodAnnotation":"PostMapping","URI":"\"users\"","className":"AdminUserResource","line":110,"otherAnnotations":["@PostMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateUser","httpMethodAnnotation":"PutMapping","URI":"\"users\"","className":"AdminUserResource","line":146,"otherAnnotations":["@PutMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getUser","httpMethodAnnotation":"GetMapping","URI":"\"users/{login:\" + Constants.LOGIN_REGEX + \"}\"","className":"AdminUserResource","line":183,"otherAnnotations":["@GetMapping(\"users/{login:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"importUsers","httpMethodAnnotation":"PostMapping","URI":"\"users/import\"","className":"AdminUserResource","line":203,"otherAnnotations":["@PostMapping(\"users/import\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"syncUserViaLdap","httpMethodAnnotation":"PutMapping","URI":"\"users/{userId}/sync-ldap\"","className":"AdminUserResource","line":217,"otherAnnotations":["@PutMapping(\"users/{userId}/sync-ldap\")","@EnforceAdmin","@Profile(\"ldap | ldap-only\")"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllUsers","httpMethodAnnotation":"GetMapping","URI":"\"users\"","className":"AdminUserResource","line":237,"otherAnnotations":["@GetMapping(\"users\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAuthorities","httpMethodAnnotation":"GetMapping","URI":"\"users/authorities\"","className":"AdminUserResource","line":250,"otherAnnotations":["@GetMapping(\"users/authorities\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteUser","httpMethodAnnotation":"DeleteMapping","URI":"\"users/{login:\" + Constants.LOGIN_REGEX + \"}\"","className":"AdminUserResource","line":262,"otherAnnotations":["@DeleteMapping(\"users/{login:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteUsers","httpMethodAnnotation":"DeleteMapping","URI":"\"users\"","className":"AdminUserResource","line":279,"otherAnnotations":["@DeleteMapping(\"users\")","@EnforceAdmin"]}]},{"filePath":"LogResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getList","httpMethodAnnotation":"GetMapping","URI":"\"logs\"","className":"LogResource","line":35,"otherAnnotations":["@GetMapping(\"logs\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"changeLevel","httpMethodAnnotation":"PutMapping","URI":"\"logs\"","className":"LogResource","line":48,"otherAnnotations":["@PutMapping(\"logs\")","@EnforceAdmin"]}]},{"filePath":"AdminPrivacyStatementResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getPrivacyStatementForUpdate","httpMethodAnnotation":"GetMapping","URI":"\"privacy-statement-for-update\"","className":"AdminPrivacyStatementResource","line":42,"otherAnnotations":["@EnforceAdmin","@GetMapping(\"privacy-statement-for-update\")"]},{"requestMapping":"\"api/admin/\"","endpoint":"updatePrivacyStatement","httpMethodAnnotation":"PutMapping","URI":"\"privacy-statement\"","className":"AdminPrivacyStatementResource","line":57,"otherAnnotations":["@EnforceAdmin","@PutMapping(\"privacy-statement\")"]}]},{"filePath":"AdminImprintResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getImprintForUpdate","httpMethodAnnotation":"GetMapping","URI":"\"imprint-for-update\"","className":"AdminImprintResource","line":42,"otherAnnotations":["@GetMapping(\"imprint-for-update\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateImprint","httpMethodAnnotation":"PutMapping","URI":"\"imprint\"","className":"AdminImprintResource","line":57,"otherAnnotations":["@PutMapping(\"imprint\")","@EnforceAdmin"]}]},{"filePath":"AuditResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getAll","httpMethodAnnotation":"GetMapping","URI":"\"audits\"","className":"AuditResource","line":50,"otherAnnotations":["@GetMapping(\"audits\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getByDates","httpMethodAnnotation":"GetMapping","URI":"\"audits\"","className":"AuditResource","line":66,"otherAnnotations":["@GetMapping(value = \"audits\", params = { \"fromDate\", \"toDate\" })","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"get","httpMethodAnnotation":"GetMapping","URI":"\"audits/{id:.+}\"","className":"AuditResource","line":85,"otherAnnotations":["@GetMapping(\"audits/{id:.+}\")","@EnforceAdmin"]}]},{"filePath":"FeatureToggleResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"toggleFeatures","httpMethodAnnotation":"PutMapping","URI":"\"feature-toggle\"","className":"FeatureToggleResource","line":38,"otherAnnotations":["@PutMapping(\"feature-toggle\")","@EnforceAdmin"]}]},{"filePath":"AdminLtiConfigurationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"getLtiPlatformConfiguration","httpMethodAnnotation":"GetMapping","URI":"\"lti-platform/{platformId}\"","className":"AdminLtiConfigurationResource","line":75,"otherAnnotations":["@GetMapping(\"lti-platform/{platformId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteLtiPlatformConfiguration","httpMethodAnnotation":"DeleteMapping","URI":"\"lti-platform/{platformId}\"","className":"AdminLtiConfigurationResource","line":89,"otherAnnotations":["@DeleteMapping(\"lti-platform/{platformId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateLtiPlatformConfiguration","httpMethodAnnotation":"PutMapping","URI":"\"lti-platform\"","className":"AdminLtiConfigurationResource","line":105,"otherAnnotations":["@PutMapping(\"lti-platform\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addLtiPlatformConfiguration","httpMethodAnnotation":"PostMapping","URI":"\"lti-platform\"","className":"AdminLtiConfigurationResource","line":125,"otherAnnotations":["@PostMapping(\"lti-platform\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"lti13DynamicRegistration","httpMethodAnnotation":"PostMapping","URI":"\"lti13/dynamic-registration\"","className":"AdminLtiConfigurationResource","line":147,"otherAnnotations":["@PostMapping(\"lti13/dynamic-registration\")","@EnforceAdmin"]}]},{"filePath":"AdminOrganizationResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"addCourseToOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations/{organizationId}/courses/{courseId}\"","className":"AdminOrganizationResource","line":74,"otherAnnotations":["@PostMapping(\"organizations/{organizationId}/courses/{courseId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"removeCourseFromOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}/courses/{courseId}\"","className":"AdminOrganizationResource","line":92,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}/courses/{courseId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addUserToOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations/{organizationId}/users/{userLogin}\"","className":"AdminOrganizationResource","line":109,"otherAnnotations":["@PostMapping(\"organizations/{organizationId}/users/{userLogin}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"removeUserFromOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}/users/{userLogin}\"","className":"AdminOrganizationResource","line":130,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}/users/{userLogin}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"addOrganization","httpMethodAnnotation":"PostMapping","URI":"\"organizations\"","className":"AdminOrganizationResource","line":147,"otherAnnotations":["@PostMapping(\"organizations\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"updateOrganization","httpMethodAnnotation":"PutMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":163,"otherAnnotations":["@PutMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteOrganization","httpMethodAnnotation":"DeleteMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":184,"otherAnnotations":["@DeleteMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"organizations\"","className":"AdminOrganizationResource","line":197,"otherAnnotations":["@GetMapping(\"organizations\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getNumberOfUsersAndCoursesByOrganization","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/count\"","className":"AdminOrganizationResource","line":212,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/count\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getNumberOfUsersAndCoursesOfAllOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"organizations/count-all\"","className":"AdminOrganizationResource","line":229,"otherAnnotations":["@GetMapping(\"organizations/count-all\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationById","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}\"","className":"AdminOrganizationResource","line":252,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationByIdWithUsersAndCourses","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/full\"","className":"AdminOrganizationResource","line":267,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/full\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getAllOrganizationsByUser","httpMethodAnnotation":"GetMapping","URI":"\"organizations/users/{userId}\"","className":"AdminOrganizationResource","line":281,"otherAnnotations":["@GetMapping(\"organizations/users/{userId}\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"getOrganizationTitle","httpMethodAnnotation":"GetMapping","URI":"\"organizations/{organizationId}/title\"","className":"AdminOrganizationResource","line":295,"otherAnnotations":["@GetMapping(\"organizations/{organizationId}/title\")","@EnforceAdmin"]}]},{"filePath":"AdminModelingExerciseResource","classRequestMapping":"\"api/admin/\"","endpoints":[{"requestMapping":"\"api/admin/\"","endpoint":"checkClusters","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/check-clusters\"","className":"AdminModelingExerciseResource","line":61,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/check-clusters\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"deleteModelingExerciseClustersAndElements","httpMethodAnnotation":"DeleteMapping","URI":"\"modeling-exercises/{exerciseId}/clusters\"","className":"AdminModelingExerciseResource","line":75,"otherAnnotations":["@DeleteMapping(\"modeling-exercises/{exerciseId}/clusters\")","@EnforceAdmin"]},{"requestMapping":"\"api/admin/\"","endpoint":"triggerAutomaticAssessment","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/{exerciseId}/trigger-automatic-assessment\"","className":"AdminModelingExerciseResource","line":93,"otherAnnotations":["@PostMapping(\"modeling-exercises/{exerciseId}/trigger-automatic-assessment\")","@EnforceAdmin"]}]},{"filePath":"SystemNotificationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllSystemNotifications","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications\"","className":"SystemNotificationResource","line":52,"otherAnnotations":["@GetMapping(\"system-notifications\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getSystemNotification","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications/{notificationId}\"","className":"SystemNotificationResource","line":67,"otherAnnotations":["@GetMapping(\"system-notifications/{notificationId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExamUserResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateExamUser","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-users\"","className":"ExamUserResource","line":75,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exam-users\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"saveUsersImages","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-users-save-images\"","className":"ExamUserResource","line":123,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exam-users-save-images\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllWhoDidNotSign","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/verify-exam-users\"","className":"ExamUserResource","line":138,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/verify-exam-users\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"isAttendanceChecked","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/attendance\"","className":"ExamUserResource","line":153,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/attendance\")","@EnforceAtLeastStudent"]}]},{"filePath":"QuizParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"startParticipation","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{exerciseId}/start-participation\"","className":"QuizParticipationResource","line":78,"otherAnnotations":["@PostMapping(\"quiz-exercises/{exerciseId}/start-participation\")","@EnforceAtLeastStudentInExercise"]}]},{"filePath":"ParticipantScoreResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getScoresOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/course-scores\"","className":"ParticipantScoreResource","line":63,"otherAnnotations":["@GetMapping(\"courses/{courseId}/course-scores\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getScoresOfExam","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/exam-scores\"","className":"ParticipantScoreResource","line":89,"otherAnnotations":["@GetMapping(\"exams/{examId}/exam-scores\")","@EnforceAtLeastInstructor"]}]},{"filePath":"AppleAppSiteAssociationResource","classRequestMapping":"\".well-known/\"","endpoints":[{"requestMapping":"\".well-known/\"","endpoint":"getAppleAppSiteAssociation","httpMethodAnnotation":"GetMapping","URI":"\"apple-app-site-association\"","className":"AppleAppSiteAssociationResource","line":35,"otherAnnotations":["@GetMapping(\"apple-app-site-association\")","@ManualConfig"]}]},{"filePath":"FileUploadAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAssessmentBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-submissions/{submissionId}/result\"","className":"FileUploadAssessmentResource","line":71,"otherAnnotations":["@Override","@GetMapping(\"file-upload-submissions/{submissionId}/result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveFileUploadAssessment","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/feedback\"","className":"FileUploadAssessmentResource","line":86,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"file-upload-submissions/{submissionId}/feedback\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateFileUploadAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/assessment-after-complaint\"","className":"FileUploadAssessmentResource","line":104,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"file-upload-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-submissions/{submissionId}/cancel-assessment\"","className":"FileUploadAssessmentResource","line":133,"otherAnnotations":["@PutMapping(\"file-upload-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/file-upload-submissions/{submissionId}/results/{resultId}\"","className":"FileUploadAssessmentResource","line":147,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/file-upload-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"PlantUmlResource","classRequestMapping":"\"api/plantuml/\"","endpoints":[{"requestMapping":"\"api/plantuml/\"","endpoint":"generatePng","httpMethodAnnotation":"GetMapping","URI":"\"png\"","className":"PlantUmlResource","line":44,"otherAnnotations":["@GetMapping(\"png\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/plantuml/\"","endpoint":"generateSvg","httpMethodAnnotation":"GetMapping","URI":"\"svg\"","className":"PlantUmlResource","line":64,"otherAnnotations":["@GetMapping(\"svg\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseSolutionEntryResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getSolutionEntry","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":95,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllSolutionEntries","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":117,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionEntriesForCodeHint","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":135,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getSolutionEntriesForTestCase","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":160,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createSolutionEntryForTestCase","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":186,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateSolutionEntry","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":212,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteSolutionEntry","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\"","className":"ProgrammingExerciseSolutionEntryResource","line":243,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/test-cases/{testCaseId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAllSolutionEntriesForExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":267,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createStructuralSolutionEntries","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/structural-solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":286,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/structural-solution-entries\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"createBehavioralSolutionEntries","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/behavioral-solution-entries\"","className":"ProgrammingExerciseSolutionEntryResource","line":309,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/behavioral-solution-entries\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseGitDiffReportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getGitDiffReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/diff-report\"","className":"ProgrammingExerciseGitDiffReportResource","line":85,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/diff-report\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report/{submissionId2}\"","className":"ProgrammingExerciseGitDiffReportResource","line":109,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report/{submissionId2}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForSubmissionWithTemplate","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report-with-template\"","className":"ProgrammingExerciseGitDiffReportResource","line":139,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/submissions/{submissionId1}/diff-report-with-template\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGitDiffReportForCommits","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/commits/{commitHash1}/diff-report/{commitHash2}\"","className":"ProgrammingExerciseGitDiffReportResource","line":169,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/commits/{commitHash1}/diff-report/{commitHash2}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseTaskResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTasks","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/tasks\"","className":"ProgrammingExerciseTaskResource","line":54,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/tasks\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTasksWithUnassignedTask","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/tasks-with-unassigned-test-cases\"","className":"ProgrammingExerciseTaskResource","line":75,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/tasks-with-unassigned-test-cases\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseHintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints\"","className":"ExerciseHintResource","line":89,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"updateExerciseHint","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":127,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getHintTitle","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/title\"","className":"ExerciseHintResource","line":169,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseHint","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":185,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints\"","className":"ExerciseHintResource","line":212,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getActivatedExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/activated\"","className":"ExerciseHintResource","line":227,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/activated\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getAvailableExerciseHintsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/available\"","className":"ExerciseHintResource","line":248,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/exercise-hints/available\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"activateExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/activate\"","className":"ExerciseHintResource","line":274,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/activate\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"rateExerciseHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/rating/{ratingValue}\"","className":"ExerciseHintResource","line":303,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}/rating/{ratingValue}\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"deleteExerciseHint","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\"","className":"ExerciseHintResource","line":327,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/exercise-hints/{exerciseHintId}\")","@EnforceAtLeastEditorInExercise"]}]},{"filePath":"CoverageReportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLatestFullCoverageReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/full-testwise-coverage-report\"","className":"CoverageReportResource","line":42,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/full-testwise-coverage-report\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getLatestCoverageReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/testwise-coverage-report\"","className":"CoverageReportResource","line":59,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/testwise-coverage-report\")","@EnforceAtLeastTutorInExercise"]}]},{"filePath":"CodeHintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllCodeHints","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/code-hints\"","className":"CodeHintResource","line":69,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/code-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"generateCodeHintsForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/code-hints\"","className":"CodeHintResource","line":83,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/code-hints\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"generateDescriptionForCodeHint","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/generate-description\"","className":"CodeHintResource","line":108,"otherAnnotations":["@Profile(\"iris\")","@PostMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/generate-description\")","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"removeSolutionEntryFromCodeHint","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries/{solutionEntryId}\"","className":"CodeHintResource","line":144,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/code-hints/{codeHintId}/solution-entries/{solutionEntryId}\")","@EnforceAtLeastEditorInExercise"]}]},{"filePath":"FileUploadSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createFileUploadSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/file-upload-submissions\"","className":"FileUploadSubmissionResource","line":108,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/file-upload-submissions\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmission","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-submissions/{submissionId}\"","className":"FileUploadSubmissionResource","line":181,"otherAnnotations":["@GetMapping(\"file-upload-submissions/{submissionId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllFileUploadSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/file-upload-submissions\"","className":"FileUploadSubmissionResource","line":233,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/file-upload-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/file-upload-submission-without-assessment\"","className":"FileUploadSubmissionResource","line":249,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/file-upload-submission-without-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getDataForFileUpload","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/file-upload-editor\"","className":"FileUploadSubmissionResource","line":299,"otherAnnotations":["@GetMapping(\"participations/{participationId}/file-upload-editor\")","@EnforceAtLeastStudent"]}]},{"filePath":"RatingResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getRatingForResult","httpMethodAnnotation":"GetMapping","URI":"\"results/{resultId}/rating\"","className":"RatingResource","line":76,"otherAnnotations":["@GetMapping(\"results/{resultId}/rating\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"createRatingForResult","httpMethodAnnotation":"PostMapping","URI":"\"results/{resultId}/rating/{ratingValue}\"","className":"RatingResource","line":95,"otherAnnotations":["@PostMapping(\"results/{resultId}/rating/{ratingValue}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateRatingForResult","httpMethodAnnotation":"PutMapping","URI":"\"results/{resultId}/rating/{ratingValue}\"","className":"RatingResource","line":117,"otherAnnotations":["@PutMapping(\"results/{resultId}/rating/{ratingValue}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getRatingForInstructorDashboard","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/rating\"","className":"RatingResource","line":132,"otherAnnotations":["@GetMapping(\"course/{courseId}/rating\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}\"","className":"ExerciseResource","line":140,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseForExampleSolution","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/example-solution\"","className":"ExerciseResource","line":192,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/example-solution\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/for-assessment-dashboard\"","className":"ExerciseResource","line":224,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseTitle","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/title\"","className":"ExerciseResource","line":262,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForExerciseAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/stats-for-assessment-dashboard\"","className":"ExerciseResource","line":275,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/stats-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"reset","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/reset\"","className":"ExerciseResource","line":291,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/reset\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseDetails","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/details\"","className":"ExerciseResource","line":307,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"toggleSecondCorrectionEnabled","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/toggle-second-correction\"","className":"ExerciseResource","line":367,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/toggle-second-correction\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestDueDate","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/latest-due-date\"","className":"ExerciseResource","line":382,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/latest-due-date\")","@EnforceAtLeastStudent"]}]},{"filePath":"TutorParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"initTutorParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/tutor-participations\"","className":"TutorParticipationResource","line":81,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/tutor-participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"assessExampleSubmissionForTutorParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/assess-example-submission\"","className":"TutorParticipationResource","line":109,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/assess-example-submission\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTutorParticipationForGuidedTour","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour/exercises/{exerciseId}/example-submission\"","className":"TutorParticipationResource","line":136,"otherAnnotations":["@DeleteMapping(\"guided-tour/exercises/{exerciseId}/example-submission\")","@EnforceAtLeastTutor"]}]},{"filePath":"TextExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTextExercise","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":202,"otherAnnotations":["@PostMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextExercise","httpMethodAnnotation":"PutMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":247,"otherAnnotations":["@PutMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getTextExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/text-exercises\"","className":"TextExerciseResource","line":301,"otherAnnotations":["@GetMapping(\"courses/{courseId}/text-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTextExercise","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}\"","className":"TextExerciseResource","line":335,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTextExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"text-exercises/{exerciseId}\"","className":"TextExerciseResource","line":371,"otherAnnotations":["@DeleteMapping(\"text-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getDataForTextEditor","httpMethodAnnotation":"GetMapping","URI":"\"text-editor/{participationId}\"","className":"TextExerciseResource","line":392,"otherAnnotations":["@GetMapping(\"text-editor/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises\"","className":"TextExerciseResource","line":475,"otherAnnotations":["@GetMapping(\"text-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises/import/{sourceExerciseId}\"","className":"TextExerciseResource","line":496,"otherAnnotations":["@PostMapping(\"text-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"text-exercises/{exerciseId}/export-submissions\"","className":"TextExerciseResource","line":534,"otherAnnotations":["@PostMapping(\"text-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}/plagiarism-result\"","className":"TextExerciseResource","line":560,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"text-exercises/{exerciseId}/check-plagiarism\"","className":"TextExerciseResource","line":582,"otherAnnotations":["@GetMapping(\"text-exercises/{exerciseId}/check-plagiarism\")","@FeatureToggle(Feature.PlagiarismChecks)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateTextExercise","httpMethodAnnotation":"PutMapping","URI":"\"text-exercises/{exerciseId}/re-evaluate\"","className":"TextExerciseResource","line":610,"otherAnnotations":["@PutMapping(\"text-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"TeamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createTeam","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/teams\"","className":"TeamResource","line":131,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/teams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTeam","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":176,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getTeam","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":247,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTeamsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/teams\"","className":"TeamResource","line":271,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/teams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTeam","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/teams/{teamId}\"","className":"TeamResource","line":290,"otherAnnotations":["@DeleteMapping(\"exercises/{exerciseId}/teams/{teamId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"existsTeamByShortName","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/teams/exists\"","className":"TeamResource","line":323,"otherAnnotations":["@GetMapping(\"courses/{courseId}/teams/exists\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"searchTeamInExercise","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/team-search-users\"","className":"TeamResource","line":340,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/team-search-users\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"importTeamsFromList","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/teams/import-from-list\"","className":"TeamResource","line":363,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/teams/import-from-list\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importTeamsFromSourceExercise","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{destinationExerciseId}/teams/import-from-exercise/{sourceExerciseId}\"","className":"TeamResource","line":402,"otherAnnotations":["@PutMapping(\"exercises/{destinationExerciseId}/teams/import-from-exercise/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithExercisesAndParticipationsForTeam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/teams/{teamShortName}/with-exercises-and-participations\"","className":"TeamResource","line":447,"otherAnnotations":["@GetMapping(\"courses/{courseId}/teams/{teamShortName}/with-exercises-and-participations\")","@EnforceAtLeastStudent"]}]},{"filePath":"BuildPlanResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBuildPlanForEditor","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-plan/for-editor\"","className":"BuildPlanResource","line":53,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-plan/for-editor\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"setBuildPlan","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/build-plan\"","className":"BuildPlanResource","line":77,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/build-plan\")","@EnforceAtLeastEditor"]}]},{"filePath":"BuildJobQueueResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getQueuedBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/queued-jobs\"","className":"BuildJobQueueResource","line":68,"otherAnnotations":["@GetMapping(\"courses/{courseId}/queued-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getRunningBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/running-jobs\"","className":"BuildJobQueueResource","line":86,"otherAnnotations":["@GetMapping(\"courses/{courseId}/running-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelBuildJob","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-job/{buildJobId}\"","className":"BuildJobQueueResource","line":105,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-job/{buildJobId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAllQueuedBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-all-queued-jobs\"","className":"BuildJobQueueResource","line":126,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-all-queued-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAllRunningBuildJobs","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cancel-all-running-jobs\"","className":"BuildJobQueueResource","line":146,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cancel-all-running-jobs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getFinishedBuildJobsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/finished-jobs\"","className":"BuildJobQueueResource","line":167,"otherAnnotations":["@GetMapping(\"courses/{courseId}/finished-jobs\")","@EnforceAtLeastInstructorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getBuildJobStatistics","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/build-job-statistics\"","className":"BuildJobQueueResource","line":184,"otherAnnotations":["@GetMapping(\"courses/{courseId}/build-job-statistics\")","@EnforceAtLeastInstructorInCourse"]}]},{"filePath":"BuildLogResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getBuildLogForBuildJob","httpMethodAnnotation":"GetMapping","URI":"\"build-log/{buildJobId}\"","className":"BuildLogResource","line":41,"otherAnnotations":["@GetMapping(\"build-log/{buildJobId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseExportImportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"importProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/import/{sourceExerciseId}\"","className":"ProgrammingExerciseExportImportResource","line":185,"otherAnnotations":["@PostMapping(\"programming-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"importProgrammingExerciseFromFile","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/programming-exercises/import-from-file\"","className":"ProgrammingExerciseExportImportResource","line":291,"otherAnnotations":["@PostMapping(\"courses/{courseId}/programming-exercises/import-from-file\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-exercise\"","className":"ProgrammingExerciseExportImportResource","line":318,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-exercise\")","@EnforceAtLeastInstructor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-repository/{repositoryType}\"","className":"ProgrammingExerciseExportImportResource","line":352,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-repository/{repositoryType}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportInstructorAuxiliaryRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-instructor-auxiliary-repository/{repositoryId}\"","className":"ProgrammingExerciseExportImportResource","line":373,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-instructor-auxiliary-repository/{repositoryId}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissionsByStudentLogins","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/export-repos-by-participant-identifiers/{participantIdentifiers}\"","className":"ProgrammingExerciseExportImportResource","line":419,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/export-repos-by-participant-identifiers/{participantIdentifiers}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissionsByParticipationIds","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/export-repos-by-participation-ids/{participationIds}\"","className":"ProgrammingExerciseExportImportResource","line":464,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/export-repos-by-participation-ids/{participationIds}\")","@EnforceAtLeastTutor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportStudentRequestedRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-student-requested-repository\"","className":"ProgrammingExerciseExportImportResource","line":523,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-student-requested-repository\")","@EnforceAtLeastStudent","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]},{"requestMapping":"\"api/\"","endpoint":"exportStudentRepository","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/export-student-repository/{participationId}\"","className":"ProgrammingExerciseExportImportResource","line":550,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/export-student-repository/{participationId}\")","@EnforceAtLeastStudent","@FeatureToggle({ Feature.ProgrammingExercises, Feature.Exports })"]}]},{"filePath":"ProgrammingAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateProgrammingManualResultAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"programming-submissions/{submissionId}/assessment-after-complaint\"","className":"ProgrammingAssessmentResource","line":80,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"programming-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"programming-submissions/{submissionId}/cancel-assessment\"","className":"ProgrammingAssessmentResource","line":116,"otherAnnotations":["@PutMapping(\"programming-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveProgrammingAssessment","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/manual-results\"","className":"ProgrammingAssessmentResource","line":130,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"participations/{participationId}/manual-results\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/programming-submissions/{submissionId}/results/{resultId}\"","className":"ProgrammingAssessmentResource","line":201,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/programming-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ProgrammingExerciseParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getParticipationWithLatestResultForStudentParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/student-participation-with-latest-result-and-feedbacks\"","className":"ProgrammingExerciseParticipationResource","line":106,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/student-participation-with-latest-result-and-feedbacks\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationWithAllResultsForStudentParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/student-participation-with-all-results\"","className":"ProgrammingExerciseParticipationResource","line":129,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/student-participation-with-all-results\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestResultWithFeedbacksForProgrammingExerciseParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/latest-result-with-feedbacks\"","className":"ProgrammingExerciseParticipationResource","line":154,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/latest-result-with-feedbacks\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"checkIfParticipationHashResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/has-result\"","className":"ProgrammingExerciseParticipationResource","line":178,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/has-result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestPendingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/latest-pending-submission\"","className":"ProgrammingExerciseParticipationResource","line":194,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/latest-pending-submission\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLatestPendingSubmissionsByExerciseId","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/latest-pending-submissions\"","className":"ProgrammingExerciseParticipationResource","line":216,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/latest-pending-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"resetRepository","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercise-participations/{participationId}/reset-repository\"","className":"ProgrammingExerciseParticipationResource","line":243,"otherAnnotations":["@PutMapping(\"programming-exercise-participations/{participationId}/reset-repository\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCommitInfosForParticipationRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/commits-info\"","className":"ProgrammingExerciseParticipationResource","line":283,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/commits-info\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCommitHistoryForParticipationRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/commit-history\"","className":"ProgrammingExerciseParticipationResource","line":299,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/commit-history\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCommitHistoryForTemplateSolutionOrTestRepo","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise/{exerciseID}/commit-history/{repositoryType}\"","className":"ProgrammingExerciseParticipationResource","line":317,"otherAnnotations":["@GetMapping(\"programming-exercise/{exerciseID}/commit-history/{repositoryType}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise-participations/{participationId}/files-content/{commitId}\"","className":"ProgrammingExerciseParticipationResource","line":350,"otherAnnotations":["@GetMapping(\"programming-exercise-participations/{participationId}/files-content/{commitId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationRepositoryFilesForCommitsDetailsView","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercise/{exerciseId}/files-content-commit-details/{commitId}\"","className":"ProgrammingExerciseParticipationResource","line":371,"otherAnnotations":["@GetMapping(\"programming-exercise/{exerciseId}/files-content-commit-details/{commitId}\")","@EnforceAtLeastStudent"]}]},{"filePath":"ProgrammingExerciseGradingResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"reEvaluateGradedResults","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/grading/re-evaluate\"","className":"ProgrammingExerciseGradingResource","line":67,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/grading/re-evaluate\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradingStatistics","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/grading/statistics\"","className":"ProgrammingExerciseGradingResource","line":90,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/grading/statistics\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createProgrammingExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/setup\"","className":"ProgrammingExerciseResource","line":229,"otherAnnotations":["@PostMapping(\"programming-exercises/setup\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises\"","className":"ProgrammingExerciseResource","line":271,"otherAnnotations":["@PutMapping(\"programming-exercises\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProgrammingExerciseTimeline","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/timeline\"","className":"ProgrammingExerciseResource","line":363,"otherAnnotations":["@PutMapping(\"programming-exercises/timeline\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateProblemStatement","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/problem-statement\"","className":"ProgrammingExerciseResource","line":387,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/problem-statement\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/programming-exercises\"","className":"ProgrammingExerciseResource","line":410,"otherAnnotations":["@GetMapping(\"courses/{courseId}/programming-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExercise","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}\"","className":"ProgrammingExerciseResource","line":442,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseWithSetupParticipations","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/with-participations\"","className":"ProgrammingExerciseResource","line":477,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/with-participations\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingExerciseWithTemplateAndSolutionParticipation","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/with-template-and-solution-participation\"","className":"ProgrammingExerciseResource","line":501,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/with-template-and-solution-participation\")","@EnforceAtLeastTutorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"deleteProgrammingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}\"","className":"ProgrammingExerciseResource","line":520,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"combineTemplateRepositoryCommits","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/combine-template-commits\"","className":"ProgrammingExerciseResource","line":543,"otherAnnotations":["@PutMapping(value = \"programming-exercises/{exerciseId}/combine-template-commits\", produces = MediaType.TEXT_PLAIN_VALUE)","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"generateStructureOracleForExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/generate-tests\"","className":"ProgrammingExerciseResource","line":566,"otherAnnotations":["@PutMapping(value = \"programming-exercises/{exerciseId}/generate-tests\", produces = MediaType.TEXT_PLAIN_VALUE)","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"hasAtLeastOneStudentResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-case-state\"","className":"ProgrammingExerciseResource","line":615,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-case-state\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises\"","className":"ProgrammingExerciseResource","line":635,"otherAnnotations":["@GetMapping(\"programming-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesWithSCAOnPage","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/with-sca\"","className":"ProgrammingExerciseResource","line":653,"otherAnnotations":["@GetMapping(\"programming-exercises/with-sca\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAuxiliaryRepositories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/auxiliary-repository\"","className":"ProgrammingExerciseResource","line":669,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/auxiliary-repository\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"reset","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/reset\"","className":"ProgrammingExerciseResource","line":691,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/reset\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateProgrammingExercise","httpMethodAnnotation":"PutMapping","URI":"\"programming-exercises/{exerciseId}/re-evaluate\"","className":"ProgrammingExerciseResource","line":730,"otherAnnotations":["@PutMapping(\"programming-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"deleteTaskWithSolutionEntries","httpMethodAnnotation":"DeleteMapping","URI":"\"programming-exercises/{exerciseId}/tasks\"","className":"ProgrammingExerciseResource","line":758,"otherAnnotations":["@DeleteMapping(\"programming-exercises/{exerciseId}/tasks\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetSolutionRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/solution-files-content\"","className":"ProgrammingExerciseResource","line":780,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/solution-files-content\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetTemplateRepositoryFiles","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/template-files-content\"","className":"ProgrammingExerciseResource","line":804,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/template-files-content\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"redirectGetSolutionRepositoryFilesWithoutContent","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/file-names\"","className":"ProgrammingExerciseResource","line":828,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/file-names\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getBuildLogStatistics","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-log-statistics\"","className":"ProgrammingExerciseResource","line":850,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-log-statistics\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getRepositoryCheckoutDirectories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/repository-checkout-directories\"","className":"ProgrammingExerciseResource","line":871,"otherAnnotations":["@GetMapping(\"programming-exercises/repository-checkout-directories\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]}]},{"filePath":"ProgrammingExerciseLockResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"unlockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/unlock-all-repositories\"","className":"ProgrammingExerciseLockResource","line":37,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/unlock-all-repositories\")","@EnforceAtLeastInstructorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"lockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/lock-all-repositories\"","className":"ProgrammingExerciseLockResource","line":53,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/lock-all-repositories\")","@EnforceAtLeastInstructorInExercise"]}]},{"filePath":"ProgrammingExerciseTestCaseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getTestCases","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/test-cases\"","className":"ProgrammingExerciseTestCaseResource","line":73,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/test-cases\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTestCases","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/update-test-cases\"","className":"ProgrammingExerciseTestCaseResource","line":93,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/update-test-cases\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"resetTestCases","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/test-cases/reset\"","className":"ProgrammingExerciseTestCaseResource","line":121,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/test-cases/reset\")","@EnforceAtLeastEditor"]}]},{"filePath":"ProgrammingExercisePlagiarismResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/plagiarism-result\"","className":"ProgrammingExercisePlagiarismResource","line":73,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/check-plagiarism\"","className":"ProgrammingExercisePlagiarismResource","line":96,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/check-plagiarism\")","@EnforceAtLeastEditor","@FeatureToggle({ Feature.ProgrammingExercises, Feature.PlagiarismChecks })"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarismWithJPlagReport","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/check-plagiarism-jplag-report\"","className":"ProgrammingExercisePlagiarismResource","line":129,"otherAnnotations":["@GetMapping(value = \"programming-exercises/{exerciseId}/check-plagiarism-jplag-report\")","@EnforceAtLeastEditor","@FeatureToggle(Feature.ProgrammingExercises)"]}]},{"filePath":"ProgrammingSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"triggerBuild","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}/trigger-build\"","className":"ProgrammingSubmissionResource","line":131,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}/trigger-build\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerFailedBuild","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}/trigger-failed-build\"","className":"ProgrammingSubmissionResource","line":172,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}/trigger-failed-build\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerInstructorBuildForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/trigger-instructor-build-all\"","className":"ProgrammingSubmissionResource","line":213,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/trigger-instructor-build-all\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"triggerInstructorBuildForExercise","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/{exerciseId}/trigger-instructor-build\"","className":"ProgrammingSubmissionResource","line":235,"otherAnnotations":["@PostMapping(\"programming-exercises/{exerciseId}/trigger-instructor-build\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getAllProgrammingSubmissions","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/programming-submissions\"","className":"ProgrammingSubmissionResource","line":267,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/programming-submissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"lockAndGetProgrammingSubmission","httpMethodAnnotation":"GetMapping","URI":"\"programming-submissions/{submissionId}/lock\"","className":"ProgrammingSubmissionResource","line":302,"otherAnnotations":["@GetMapping(\"programming-submissions/{submissionId}/lock\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getProgrammingSubmissionWithoutAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/programming-submission-without-assessment\"","className":"ProgrammingSubmissionResource","line":367,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/programming-submission-without-assessment\")","@EnforceAtLeastTutor"]}]},{"filePath":"ComplaintResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createComplaint","httpMethodAnnotation":"PostMapping","URI":"\"complaints\"","className":"ComplaintResource","line":107,"otherAnnotations":["@PostMapping(\"complaints\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":151,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"submissionId\" })","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsForTestRunDashboard","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":196,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"exerciseId\" })","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByCourseId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":215,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"courseId\", \"complaintType\" })","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByExerciseId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":257,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"exerciseId\", \"complaintType\" })","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getComplaintsByCourseIdAndExamId","httpMethodAnnotation":"GetMapping","URI":"\"complaints\"","className":"ComplaintResource","line":294,"otherAnnotations":["@GetMapping(value = \"complaints\", params = { \"courseId\", \"examId\" })","@EnforceAtLeastInstructor"]}]},{"filePath":"ModelingAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAssessmentBySubmissionId","httpMethodAnnotation":"GetMapping","URI":"\"modeling-submissions/{submissionId}/result\"","className":"ModelingAssessmentResource","line":85,"otherAnnotations":["@Override","@GetMapping(\"modeling-submissions/{submissionId}/result\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExampleAssessment","httpMethodAnnotation":"GetMapping","URI":"\"exercise/{exerciseId}/modeling-submissions/{submissionId}/example-assessment\"","className":"ModelingAssessmentResource","line":99,"otherAnnotations":["@GetMapping(\"exercise/{exerciseId}/modeling-submissions/{submissionId}/example-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveModelingAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/result/{resultId}/assessment\"","className":"ModelingAssessmentResource","line":115,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = PUT_SUBMIT_ASSESSMENT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{submissionId}/result/{resultId}/assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveModelingExampleAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{exampleSubmissionId}/example-assessment\"","className":"ModelingAssessmentResource","line":133,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = PUT_SUBMIT_ASSESSMENT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{exampleSubmissionId}/example-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/assessment-after-complaint\"","className":"ModelingAssessmentResource","line":152,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 200, message = POST_ASSESSMENT_AFTER_COMPLAINT_200_REASON, response = Result.class), @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"modeling-submissions/{submissionId}/assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PutMapping","URI":"\"modeling-submissions/{submissionId}/cancel-assessment\"","className":"ModelingAssessmentResource","line":187,"otherAnnotations":["@PutMapping(\"modeling-submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/modeling-submissions/{submissionId}/results/{resultId}\"","className":"ModelingAssessmentResource","line":201,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/modeling-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"CourseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}\"","className":"CourseResource","line":228,"otherAnnotations":["@PutMapping(value = \"courses/{courseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateOnlineCourseConfiguration","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/onlineCourseConfiguration\"","className":"CourseResource","line":373,"otherAnnotations":["@PutMapping(\"courses/{courseId}/onlineCourseConfiguration\")","@EnforceAtLeastInstructor","@Profile(\"lti\")"]},{"requestMapping":"\"api/\"","endpoint":"findAllOnlineCoursesForLtiDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-lti-dashboard\"","className":"CourseResource","line":415,"otherAnnotations":["@GetMapping(\"courses/for-lti-dashboard\")","@EnforceAtLeastInstructor","@Profile(\"lti\")"]},{"requestMapping":"\"api/\"","endpoint":"enrollInCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/enroll\"","className":"CourseResource","line":439,"otherAnnotations":["@PostMapping(\"courses/{courseId}/enroll\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"unenrollFromCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/unenroll\"","className":"CourseResource","line":458,"otherAnnotations":["@PostMapping(\"courses/{courseId}/unenroll\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourses","httpMethodAnnotation":"GetMapping","URI":"\"courses\"","className":"CourseResource","line":474,"otherAnnotations":["@GetMapping(\"courses\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForImport","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-import\"","className":"CourseResource","line":496,"otherAnnotations":["@GetMapping(\"courses/for-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesWithQuizExercises","httpMethodAnnotation":"GetMapping","URI":"\"courses/courses-with-quiz\"","className":"CourseResource","line":511,"otherAnnotations":["@GetMapping(\"courses/courses-with-quiz\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesWithUserStats","httpMethodAnnotation":"GetMapping","URI":"\"courses/with-user-stats\"","className":"CourseResource","line":530,"otherAnnotations":["@GetMapping(\"courses/with-user-stats\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForManagementOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/course-management-overview\"","className":"CourseResource","line":551,"otherAnnotations":["@GetMapping(\"courses/course-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForEnrollment","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-enrollment\"","className":"CourseResource","line":563,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-enrollment\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForEnrollment","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-enrollment\"","className":"CourseResource","line":581,"otherAnnotations":["@GetMapping(\"courses/for-enrollment\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-dashboard\"","className":"CourseResource","line":598,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-dashboard\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForDropdown","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-dropdown\"","className":"CourseResource","line":639,"otherAnnotations":["@GetMapping(\"courses/for-dropdown\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-dashboard\"","className":"CourseResource","line":662,"otherAnnotations":["@GetMapping(\"courses/for-dashboard\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCoursesForNotifications","httpMethodAnnotation":"GetMapping","URI":"\"courses/for-notifications\"","className":"CourseResource","line":712,"otherAnnotations":["@GetMapping(\"courses/for-notifications\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/for-assessment-dashboard\"","className":"CourseResource","line":726,"otherAnnotations":["@GetMapping(\"courses/{courseId}/for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/stats-for-assessment-dashboard\"","className":"CourseResource","line":751,"otherAnnotations":["@GetMapping(\"courses/{courseId}/stats-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}\"","className":"CourseResource","line":766,"otherAnnotations":["@GetMapping(\"courses/{courseId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithExercises","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/with-exercises\"","className":"CourseResource","line":798,"otherAnnotations":["@GetMapping(\"courses/{courseId}/with-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseWithOrganizations","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/with-organizations\"","className":"CourseResource","line":813,"otherAnnotations":["@GetMapping(\"courses/{courseId}/with-organizations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLockedSubmissionsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lockedSubmissions\"","className":"CourseResource","line":828,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lockedSubmissions\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExercisesForCourseOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/exercises-for-management-overview\"","className":"CourseResource","line":852,"otherAnnotations":["@GetMapping(\"courses/exercises-for-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStatsForCourseOverview","httpMethodAnnotation":"GetMapping","URI":"\"courses/stats-for-management-overview\"","className":"CourseResource","line":873,"otherAnnotations":["@GetMapping(\"courses/stats-for-management-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"archiveCourse","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/archive\"","className":"CourseResource","line":903,"otherAnnotations":["@PutMapping(\"courses/{courseId}/archive\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"downloadCourseArchive","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/download-archive\"","className":"CourseResource","line":934,"otherAnnotations":["@EnforceAtLeastInstructor","@GetMapping(\"courses/{courseId}/download-archive\")"]},{"requestMapping":"\"api/\"","endpoint":"cleanup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/cleanup\"","className":"CourseResource","line":963,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/cleanup\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCategoriesInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/categories\"","className":"CourseResource","line":983,"otherAnnotations":["@GetMapping(\"courses/{courseId}/categories\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/students\"","className":"CourseResource","line":998,"otherAnnotations":["@GetMapping(\"courses/{courseId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"searchStudentsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/students/search\"","className":"CourseResource","line":1013,"otherAnnotations":["@GetMapping(\"courses/{courseId}/students/search\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"searchUsersInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/users/search\"","className":"CourseResource","line":1036,"otherAnnotations":["@GetMapping(\"courses/{courseId}/users/search\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTutorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/tutors\"","className":"CourseResource","line":1082,"otherAnnotations":["@GetMapping(\"courses/{courseId}/tutors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getEditorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/editors\"","className":"CourseResource","line":1096,"otherAnnotations":["@GetMapping(\"courses/{courseId}/editors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getInstructorsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/instructors\"","className":"CourseResource","line":1110,"otherAnnotations":["@GetMapping(\"courses/{courseId}/instructors\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"searchOtherUsersInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/search-other-users\"","className":"CourseResource","line":1125,"otherAnnotations":["@GetMapping(\"courses/{courseId}/search-other-users\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"searchMembersOfCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/members/search\"","className":"CourseResource","line":1146,"otherAnnotations":["@GetMapping(\"courses/{courseId}/members/search\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getCourseTitle","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/title\"","className":"CourseResource","line":1167,"otherAnnotations":["@GetMapping(\"courses/{courseId}/title\")","@EnforceAtLeastStudent","@ResponseBody"]},{"requestMapping":"\"api/\"","endpoint":"addStudentToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1182,"otherAnnotations":["@PostMapping(\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addTutorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1197,"otherAnnotations":["@PostMapping(\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addEditorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1212,"otherAnnotations":["@PostMapping(\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addInstructorToCourse","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1228,"otherAnnotations":["@PostMapping(\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeStudentFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1272,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeTutorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1287,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/tutors/{tutorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeEditorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1302,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/editors/{editorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeInstructorFromCourse","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"CourseResource","line":1318,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/instructors/{instructorLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getCourseDTOForDetailView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/management-detail\"","className":"CourseResource","line":1354,"otherAnnotations":["@GetMapping(\"courses/{courseId}/management-detail\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getActiveStudentsForCourseDetailView","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/statistics\"","className":"CourseResource","line":1372,"otherAnnotations":["@GetMapping(\"courses/{courseId}/statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getActiveStudentsForCourseLiveTime","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/statistics-lifetime-overview\"","className":"CourseResource","line":1392,"otherAnnotations":["@GetMapping(\"courses/{courseId}/statistics-lifetime-overview\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"addUsersToCourseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/{courseGroup}\"","className":"CourseResource","line":1419,"otherAnnotations":["@PostMapping(\"courses/{courseId}/{courseGroup}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfAllowedComplaintsInCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/allowed-complaints\"","className":"CourseResource","line":1438,"otherAnnotations":["@GetMapping(\"courses/{courseId}/allowed-complaints\")","@EnforceAtLeastStudent"]}]},{"filePath":"ParticipationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"startParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":209,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastStudentInExercise"]},{"requestMapping":"\"api/\"","endpoint":"startPracticeParticipation","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/participations/practice\"","className":"ParticipationResource","line":266,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/participations/practice\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"resumeParticipation","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/resume-programming-participation/{participationId}\"","className":"ParticipationResource","line":309,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/resume-programming-participation/{participationId}\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"requestFeedback","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/request-feedback\"","className":"ParticipationResource","line":352,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/request-feedback\")","@EnforceAtLeastStudent","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipation","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":430,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateParticipationDueDates","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/participations/update-individual-due-date\"","className":"ParticipationResource","line":510,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/participations/update-individual-due-date\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllParticipationsForExercise","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/participations\"","className":"ParticipationResource","line":571,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/participations\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getAllParticipationsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/participations\"","className":"ParticipationResource","line":613,"otherAnnotations":["@GetMapping(\"courses/{courseId}/participations\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationWithLatestResult","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/withLatestResult\"","className":"ParticipationResource","line":674,"otherAnnotations":["@GetMapping(\"participations/{participationId}/withLatestResult\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}\"","className":"ParticipationResource","line":696,"otherAnnotations":["@GetMapping(\"participations/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationBuildArtifact","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/buildArtifact\"","className":"ParticipationResource","line":712,"otherAnnotations":["@GetMapping(\"participations/{participationId}/buildArtifact\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getParticipationForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/participation\"","className":"ParticipationResource","line":731,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/participation\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteParticipation","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}\"","className":"ParticipationResource","line":819,"otherAnnotations":["@DeleteMapping(\"participations/{participationId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteParticipationForGuidedTour","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour/participations/{participationId}\"","className":"ParticipationResource","line":842,"otherAnnotations":["@DeleteMapping(\"guided-tour/participations/{participationId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"cleanupBuildPlan","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/cleanupBuildPlan\"","className":"ParticipationResource","line":894,"otherAnnotations":["@PutMapping(\"participations/{participationId}/cleanupBuildPlan\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.ProgrammingExercises)"]},{"requestMapping":"\"api/\"","endpoint":"getSubmissionsOfParticipation","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/submissions\"","className":"ParticipationResource","line":937,"otherAnnotations":["@GetMapping(\"participations/{participationId}/submissions\")","@EnforceAtLeastInstructor"]}]},{"filePath":"OrganizationResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllOrganizationsByCourse","httpMethodAnnotation":"GetMapping","URI":"\"organizations/courses/{courseId}\"","className":"OrganizationResource","line":43,"otherAnnotations":["@GetMapping(\"organizations/courses/{courseId}\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseScoresChartResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getCourseExerciseScores","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/charts/exercise-scores\"","className":"ExerciseScoresChartResource","line":71,"otherAnnotations":["@GetMapping(\"courses/{courseId}/charts/exercise-scores\")","@EnforceAtLeastStudent"]}]},{"filePath":"TextAssessmentEventResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"addAssessmentEvent","httpMethodAnnotation":"PostMapping","URI":"\"event-insights/text-assessment/events\"","className":"TextAssessmentEventResource","line":83,"otherAnnotations":["@PostMapping(\"event-insights/text-assessment/events\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getNumberOfTutorsInvolved","httpMethodAnnotation":"GetMapping","URI":"\"event-insights/text-assessment/courses/{courseId}/text-exercises/{exerciseId}/tutors-involved\"","className":"TextAssessmentEventResource","line":105,"otherAnnotations":["@GetMapping(\"event-insights/text-assessment/courses/{courseId}/text-exercises/{exerciseId}/tutors-involved\")","@EnforceAtLeastInstructor"]}]},{"filePath":"TutorEffortResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"calculateTutorEfforts","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exercises/{exerciseId}/tutor-effort\"","className":"TutorEffortResource","line":64,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exercises/{exerciseId}/tutor-effort\")","@EnforceAtLeastInstructor"]}]},{"filePath":"NotificationSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getNotificationSettingsForCurrentUser","httpMethodAnnotation":"GetMapping","URI":"\"notification-settings\"","className":"NotificationSettingsResource","line":67,"otherAnnotations":["@GetMapping(\"notification-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"saveNotificationSettingsForCurrentUser","httpMethodAnnotation":"PutMapping","URI":"\"notification-settings\"","className":"NotificationSettingsResource","line":88,"otherAnnotations":["@PutMapping(\"notification-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getMutedConversations","httpMethodAnnotation":"GetMapping","URI":"\"muted-conversations\"","className":"NotificationSettingsResource","line":110,"otherAnnotations":["@GetMapping(\"muted-conversations\")","@EnforceAtLeastStudent"]}]},{"filePath":"ExampleSubmissionResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExampleSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions\"","className":"ExampleSubmissionResource","line":88,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateExampleSubmission","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/example-submissions\"","className":"ExampleSubmissionResource","line":107,"otherAnnotations":["@PutMapping(\"exercises/{exerciseId}/example-submissions\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"prepareExampleAssessment","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/prepare-assessment\"","className":"ExampleSubmissionResource","line":126,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/prepare-assessment\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExampleSubmission","httpMethodAnnotation":"GetMapping","URI":"\"example-submissions/{exampleSubmissionId}\"","className":"ExampleSubmissionResource","line":166,"otherAnnotations":["@GetMapping(\"example-submissions/{exampleSubmissionId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExampleSubmission","httpMethodAnnotation":"DeleteMapping","URI":"\"example-submissions/{exampleSubmissionId}\"","className":"ExampleSubmissionResource","line":189,"otherAnnotations":["@DeleteMapping(\"example-submissions/{exampleSubmissionId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExampleSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/example-submissions/import/{sourceSubmissionId}\"","className":"ExampleSubmissionResource","line":207,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/example-submissions/import/{sourceSubmissionId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"FileUploadExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createFileUploadExercise","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises\"","className":"FileUploadExerciseResource","line":143,"otherAnnotations":["@PostMapping(\"file-upload-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importFileUploadExercise","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises/import/{sourceId}\"","className":"FileUploadExerciseResource","line":181,"otherAnnotations":["@PostMapping(\"file-upload-exercises/import/{sourceId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-exercises\"","className":"FileUploadExerciseResource","line":242,"otherAnnotations":["@GetMapping(\"file-upload-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateFileUploadExercise","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":259,"otherAnnotations":["@PutMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/file-upload-exercises\"","className":"FileUploadExerciseResource","line":301,"otherAnnotations":["@GetMapping(value = \"courses/{courseId}/file-upload-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getFileUploadExercise","httpMethodAnnotation":"GetMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":322,"otherAnnotations":["@GetMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteFileUploadExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"file-upload-exercises/{exerciseId}\"","className":"FileUploadExerciseResource","line":356,"otherAnnotations":["@DeleteMapping(\"file-upload-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"file-upload-exercises/{exerciseId}/export-submissions\"","className":"FileUploadExerciseResource","line":376,"otherAnnotations":["@PostMapping(\"file-upload-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateFileUploadExercise","httpMethodAnnotation":"PutMapping","URI":"\"file-upload-exercises/{exerciseId}/re-evaluate\"","className":"FileUploadExerciseResource","line":403,"otherAnnotations":["@PutMapping(\"file-upload-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"ExamLockResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"unlockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/unlock-all-repositories\"","className":"ExamLockResource","line":42,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/unlock-all-repositories\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"lockAllRepositories","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/lock-all-repositories\"","className":"ExamLockResource","line":61,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/lock-all-repositories\")","@EnforceAtLeastInstructor"]}]},{"filePath":"ApollonDiagramResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createApollonDiagram","httpMethodAnnotation":"PostMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":67,"otherAnnotations":["@PostMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateApollonDiagram","httpMethodAnnotation":"PutMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":96,"otherAnnotations":["@PutMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getDiagramTitle","httpMethodAnnotation":"GetMapping","URI":"\"apollon-diagrams/{diagramId}/title\"","className":"ApollonDiagramResource","line":121,"otherAnnotations":["@GetMapping(\"apollon-diagrams/{diagramId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getDiagramsByCourse","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/apollon-diagrams\"","className":"ApollonDiagramResource","line":134,"otherAnnotations":["@GetMapping(\"course/{courseId}/apollon-diagrams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getApollonDiagram","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\"","className":"ApollonDiagramResource","line":152,"otherAnnotations":["@GetMapping(\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteApollonDiagram","httpMethodAnnotation":"DeleteMapping","URI":"\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\"","className":"ApollonDiagramResource","line":171,"otherAnnotations":["@DeleteMapping(\"course/{courseId}/apollon-diagrams/{apollonDiagramId}\")","@EnforceAtLeastEditor"]}]},{"filePath":"TextAssessmentResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"saveTextAssessment","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/results/{resultId}/text-assessment\"","className":"TextAssessmentResource","line":133,"otherAnnotations":["@PutMapping(\"participations/{participationId}/results/{resultId}/text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"saveTextExampleAssessment","httpMethodAnnotation":"PutMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment\"","className":"TextAssessmentResource","line":167,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@ApiResponses({ @ApiResponse(code = 403, message = ErrorConstants.REQ_403_REASON), @ApiResponse(code = 404, message = ErrorConstants.REQ_404_REASON) })","@PutMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTextExampleAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment/feedback\"","className":"TextAssessmentResource","line":201,"otherAnnotations":["@ResponseStatus(HttpStatus.NO_CONTENT)","@DeleteMapping(\"exercises/{exerciseId}/example-submissions/{exampleSubmissionId}/example-text-assessment/feedback\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"submitTextAssessment","httpMethodAnnotation":"PostMapping","URI":"\"participations/{participationId}/results/{resultId}/submit-text-assessment\"","className":"TextAssessmentResource","line":244,"otherAnnotations":["@PostMapping(\"participations/{participationId}/results/{resultId}/submit-text-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateTextAssessmentAfterComplaint","httpMethodAnnotation":"PutMapping","URI":"\"participations/{participationId}/submissions/{submissionId}/text-assessment-after-complaint\"","className":"TextAssessmentResource","line":282,"otherAnnotations":["@ResponseStatus(HttpStatus.OK)","@PutMapping(\"participations/{participationId}/submissions/{submissionId}/text-assessment-after-complaint\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"cancelAssessment","httpMethodAnnotation":"PostMapping","URI":"\"participations/{participationId}/submissions/{submissionId}/cancel-assessment\"","className":"TextAssessmentResource","line":316,"otherAnnotations":["@PostMapping(\"participations/{participationId}/submissions/{submissionId}/cancel-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteAssessment","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/text-submissions/{submissionId}/results/{resultId}\"","className":"TextAssessmentResource","line":336,"otherAnnotations":["@Override","@DeleteMapping(\"participations/{participationId}/text-submissions/{submissionId}/results/{resultId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"retrieveParticipationForSubmission","httpMethodAnnotation":"GetMapping","URI":"\"text-submissions/{submissionId}/for-assessment\"","className":"TextAssessmentResource","line":356,"otherAnnotations":["@GetMapping(\"text-submissions/{submissionId}/for-assessment\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExampleResultForTutor","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/submissions/{submissionId}/example-result\"","className":"TextAssessmentResource","line":432,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/submissions/{submissionId}/example-result\")","@EnforceAtLeastTutor"]}]},{"filePath":"ExerciseGroupResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExerciseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":95,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateExerciseGroup","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":132,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExerciseGroup","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/import-exercise-group\"","className":"ExerciseGroupResource","line":159,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/import-exercise-group\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseGroup","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\"","className":"ExerciseGroupResource","line":180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseGroupsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups\"","className":"ExerciseGroupResource","line":198,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExerciseGroup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\"","className":"ExerciseGroupResource","line":221,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/exerciseGroups/{exerciseGroupId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"LectureResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createLecture","httpMethodAnnotation":"PostMapping","URI":"\"lectures\"","className":"LectureResource","line":109,"otherAnnotations":["@PostMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateLecture","httpMethodAnnotation":"PutMapping","URI":"\"lectures\"","className":"LectureResource","line":130,"otherAnnotations":["@PutMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllLecturesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"lectures\"","className":"LectureResource","line":157,"otherAnnotations":["@GetMapping(\"lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLecturesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lectures\"","className":"LectureResource","line":171,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lectures\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLecturesWithSlidesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/lectures-with-slides\"","className":"LectureResource","line":195,"otherAnnotations":["@GetMapping(\"courses/{courseId}/lectures-with-slides\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLecture","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}\"","className":"LectureResource","line":216,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"importLecture","httpMethodAnnotation":"PostMapping","URI":"\"lectures/import/{sourceLectureId}\"","className":"LectureResource","line":242,"otherAnnotations":["@PostMapping(\"lectures/import/{sourceLectureId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"ingestLectures","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/ingest\"","className":"LectureResource","line":271,"otherAnnotations":["@PostMapping(\"courses/{courseId}/ingest\")"]},{"requestMapping":"\"api/\"","endpoint":"getLectureWithDetails","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/details\"","className":"LectureResource","line":295,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureWithDetailsAndSlides","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/details-with-slides\"","className":"LectureResource","line":317,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/details-with-slides\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getLectureTitle","httpMethodAnnotation":"GetMapping","URI":"\"lectures/{lectureId}/title\"","className":"LectureResource","line":340,"otherAnnotations":["@GetMapping(\"lectures/{lectureId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteLecture","httpMethodAnnotation":"DeleteMapping","URI":"\"lectures/{lectureId}\"","className":"LectureResource","line":395,"otherAnnotations":["@DeleteMapping(\"lectures/{lectureId}\")","@EnforceAtLeastInstructor"]}]},{"filePath":"StaticCodeAnalysisResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getStaticCodeAnalysisCategories","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories\"","className":"StaticCodeAnalysisResource","line":69,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"updateStaticCodeAnalysisCategories","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories\"","className":"StaticCodeAnalysisResource","line":89,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"resetStaticCodeAnalysisCategories","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}/static-code-analysis-categories/reset\"","className":"StaticCodeAnalysisResource","line":111,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}/static-code-analysis-categories/reset\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importStaticCodeAnalysisCategoriesFromExercise","httpMethodAnnotation":"PatchMapping","URI":"\"programming-exercises/{exerciseId}\" + \"/static-code-analysis-categories/import\"","className":"StaticCodeAnalysisResource","line":132,"otherAnnotations":["@PatchMapping(\"programming-exercises/{exerciseId}\" + \"/static-code-analysis-categories/import\")","@EnforceAtLeastEditor"]}]},{"filePath":"LongFeedbackTextResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getLongFeedback","httpMethodAnnotation":"GetMapping","URI":"\"results/{resultId}/feedbacks/{feedbackId}/long-feedback\"","className":"LongFeedbackTextResource","line":46,"otherAnnotations":["@GetMapping(\"results/{resultId}/feedbacks/{feedbackId}/long-feedback\")","@EnforceAtLeastStudent"]}]},{"filePath":"GradeStepResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getAllGradeStepsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/grade-steps\"","className":"GradeStepResource","line":84,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/grade-steps\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getAllGradeStepsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps\"","className":"GradeStepResource","line":105,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepsByIdForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/grade-steps/{gradeStepId}\"","className":"GradeStepResource","line":138,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/grade-steps/{gradeStepId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepsByIdForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps/{gradeStepId}\"","className":"GradeStepResource","line":157,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/grade-steps/{gradeStepId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepByPercentageForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/grading-scale/match-grade-step\"","className":"GradeStepResource","line":175,"otherAnnotations":["@GetMapping(\"courses/{courseId}/grading-scale/match-grade-step\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getGradeStepByPercentageForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/grading-scale/match-grade-step\"","className":"GradeStepResource","line":212,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/grading-scale/match-grade-step\")","@EnforceAtLeastStudent"]}]},{"filePath":"QuizExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createQuizExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises\"","className":"QuizExerciseResource","line":215,"otherAnnotations":["@PostMapping(value = \"quiz-exercises\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{exerciseId}\"","className":"QuizExerciseResource","line":260,"otherAnnotations":["@PutMapping(value = \"quiz-exercises/{exerciseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditorInExercise"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/quiz-exercises\"","className":"QuizExerciseResource","line":320,"otherAnnotations":["@GetMapping(\"courses/{courseId}/quiz-exercises\")","@EnforceAtLeastTutorInCourse"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercisesForExam","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/quiz-exercises\"","className":"QuizExerciseResource","line":344,"otherAnnotations":["@GetMapping(\"exams/{examId}/quiz-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExercise","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}\"","className":"QuizExerciseResource","line":368,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"recalculateStatistics","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}/recalculate-statistics\"","className":"QuizExerciseResource","line":395,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}/recalculate-statistics\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"getQuizExerciseForStudent","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises/{quizExerciseId}/for-student\"","className":"QuizExerciseResource","line":411,"otherAnnotations":["@GetMapping(\"quiz-exercises/{quizExerciseId}/for-student\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"joinBatch","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{quizExerciseId}/join\"","className":"QuizExerciseResource","line":437,"otherAnnotations":["@PostMapping(\"quiz-exercises/{quizExerciseId}/join\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"addBatch","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/add-batch\"","className":"QuizExerciseResource","line":465,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizExerciseId}/add-batch\")","@EnforceAtLeastTutorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"startBatch","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizBatchId}/start-batch\"","className":"QuizExerciseResource","line":491,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizBatchId}/start-batch\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"performActionForQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/{action}\"","className":"QuizExerciseResource","line":528,"otherAnnotations":["@PutMapping(\"quiz-exercises/{quizExerciseId}/{action}\")","@EnforceAtLeastEditorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"evaluateQuizExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/{quizExerciseId}/evaluate\"","className":"QuizExerciseResource","line":638,"otherAnnotations":["@PostMapping(\"quiz-exercises/{quizExerciseId}/evaluate\")","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"deleteQuizExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"quiz-exercises/{quizExerciseId}\"","className":"QuizExerciseResource","line":658,"otherAnnotations":["@DeleteMapping(\"quiz-exercises/{quizExerciseId}\")","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateQuizExercise","httpMethodAnnotation":"PutMapping","URI":"\"quiz-exercises/{quizExerciseId}/re-evaluate\"","className":"QuizExerciseResource","line":706,"otherAnnotations":["@PutMapping(value = \"quiz-exercises/{quizExerciseId}/re-evaluate\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastInstructorInExercise(resourceIdFieldName = \"quizExerciseId\")"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"quiz-exercises\"","className":"QuizExerciseResource","line":745,"otherAnnotations":["@GetMapping(\"quiz-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"quiz-exercises/import/{sourceExerciseId}\"","className":"QuizExerciseResource","line":766,"otherAnnotations":["@PostMapping(value = \"quiz-exercises/import/{sourceExerciseId}\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)","@EnforceAtLeastEditor"]}]},{"filePath":"ModelingExerciseResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createModelingExercise","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":160,"otherAnnotations":["@PostMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesOnPage","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":199,"otherAnnotations":["@GetMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"updateModelingExercise","httpMethodAnnotation":"PutMapping","URI":"\"modeling-exercises\"","className":"ModelingExerciseResource","line":216,"otherAnnotations":["@PutMapping(\"modeling-exercises\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExercisesForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/modeling-exercises\"","className":"ModelingExerciseResource","line":266,"otherAnnotations":["@GetMapping(\"courses/{courseId}/modeling-exercises\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getModelingExercise","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}\"","className":"ModelingExerciseResource","line":297,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteModelingExercise","httpMethodAnnotation":"DeleteMapping","URI":"\"modeling-exercises/{exerciseId}\"","className":"ModelingExerciseResource","line":324,"otherAnnotations":["@DeleteMapping(\"modeling-exercises/{exerciseId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"importExercise","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/import/{sourceExerciseId}\"","className":"ModelingExerciseResource","line":353,"otherAnnotations":["@PostMapping(\"modeling-exercises/import/{sourceExerciseId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"exportSubmissions","httpMethodAnnotation":"PostMapping","URI":"\"modeling-exercises/{exerciseId}/export-submissions\"","className":"ModelingExerciseResource","line":381,"otherAnnotations":["@PostMapping(\"modeling-exercises/{exerciseId}/export-submissions\")","@EnforceAtLeastTutor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"getPlagiarismResult","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/plagiarism-result\"","className":"ModelingExerciseResource","line":407,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/plagiarism-result\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"checkPlagiarism","httpMethodAnnotation":"GetMapping","URI":"\"modeling-exercises/{exerciseId}/check-plagiarism\"","className":"ModelingExerciseResource","line":430,"otherAnnotations":["@GetMapping(\"modeling-exercises/{exerciseId}/check-plagiarism\")","@FeatureToggle(Feature.PlagiarismChecks)","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"reEvaluateAndUpdateModelingExercise","httpMethodAnnotation":"PutMapping","URI":"\"modeling-exercises/{exerciseId}/re-evaluate\"","className":"ModelingExerciseResource","line":458,"otherAnnotations":["@PutMapping(\"modeling-exercises/{exerciseId}/re-evaluate\")","@EnforceAtLeastEditor"]}]},{"filePath":"StudentExamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getStudentExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}\"","className":"StudentExamResource","line":175,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams\"","className":"StudentExamResource","line":212,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateWorkingTime","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/working-time\"","className":"StudentExamResource","line":233,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/working-time\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"attendanceCheck","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}/attendance-check\"","className":"StudentExamResource","line":274,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}/attendance-check\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"submitStudentExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/submit\"","className":"StudentExamResource","line":309,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/submit\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamForConduction","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/conduction\"","className":"StudentExamResource","line":361,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/conduction\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getTestRunForConduction","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run/{testRunId}/conduction\"","className":"StudentExamResource","line":424,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/test-run/{testRunId}/conduction\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamsForCoursePerUser","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/test-exams-per-user\"","className":"StudentExamResource","line":460,"otherAnnotations":["@GetMapping(\"courses/{courseId}/test-exams-per-user\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamForSummary","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/summary\"","className":"StudentExamResource","line":481,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/summary\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getStudentExamGradesForSummary","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/grade-summary\"","className":"StudentExamResource","line":528,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/grade-summary\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExamLiveEvents","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/live-events\"","className":"StudentExamResource","line":558,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/live-events\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"findAllTestRunsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/test-runs\"","className":"StudentExamResource","line":588,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/test-runs\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createTestRun","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run\"","className":"StudentExamResource","line":607,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/test-run\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"assessUnsubmittedStudentExamsAndEmptySubmissions","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/assess-unsubmitted-and-empty-student-exams\"","className":"StudentExamResource","line":633,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/assess-unsubmitted-and-empty-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteTestRun","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/test-run/{testRunId}\"","className":"StudentExamResource","line":668,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/test-run/{testRunId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"startExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/start-exercises\"","className":"StudentExamResource","line":687,"otherAnnotations":["@PostMapping(value = \"courses/{courseId}/exams/{examId}/student-exams/start-exercises\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExerciseStartStatus","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/start-exercises/status\"","className":"StudentExamResource","line":726,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/student-exams/start-exercises/status\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"submitStudentExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-submitted\"","className":"StudentExamResource","line":829,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-submitted\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"unsubmitStudentExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-unsubmitted\"","className":"StudentExamResource","line":866,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/student-exams/{studentExamId}/toggle-to-unsubmitted\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getLongestWorkingTimeForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/longest-working-time\"","className":"StudentExamResource","line":901,"otherAnnotations":["@EnforceAtLeastInstructor","@GetMapping(\"courses/{courseId}/exams/{examId}/longest-working-time\")"]}]},{"filePath":"PublicBuildPlanResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getBuildPlan","httpMethodAnnotation":"GetMapping","URI":"\"programming-exercises/{exerciseId}/build-plan\"","className":"PublicBuildPlanResource","line":41,"otherAnnotations":["@GetMapping(\"programming-exercises/{exerciseId}/build-plan\")","@EnforceNothing"]}]},{"filePath":"PublicResultResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"processNewProgrammingExerciseResult","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/new-result\"","className":"PublicResultResource","line":83,"otherAnnotations":["@PostMapping(\"programming-exercises/new-result\")","@EnforceNothing"]}]},{"filePath":"PublicSystemNotificationResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getActiveAndFutureSystemNotifications","httpMethodAnnotation":"GetMapping","URI":"\"system-notifications/active\"","className":"PublicSystemNotificationResource","line":41,"otherAnnotations":["@GetMapping(\"system-notifications/active\")","@EnforceNothing"]}]},{"filePath":"PublicPyrisStatusUpdateResource","classRequestMapping":"\"api/public/pyris/\"","endpoints":[{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfJob","httpMethodAnnotation":"PostMapping","URI":"\"pipelines/tutor-chat/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":58,"otherAnnotations":["// TODO: Rename this to 'exercise-chat' with next breaking Pyris version\n@PostMapping(\"pipelines/tutor-chat/runs/{runId}/status\")","@EnforceNothing"]},{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfCourseChatJob","httpMethodAnnotation":"PostMapping","URI":"\"pipelines/course-chat/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":86,"otherAnnotations":["@PostMapping(\"pipelines/course-chat/runs/{runId}/status\")","@EnforceNothing"]},{"requestMapping":"\"api/public/pyris/\"","endpoint":"setStatusOfIngestionJob","httpMethodAnnotation":"PostMapping","URI":"\"webhooks/ingestion/runs/{runId}/status\"","className":"PublicPyrisStatusUpdateResource","line":112,"otherAnnotations":["@PostMapping(\"webhooks/ingestion/runs/{runId}/status\")","@EnforceNothing"]}]},{"filePath":"PublicProgrammingSubmissionResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"processNewProgrammingSubmission","httpMethodAnnotation":"PostMapping","URI":"\"programming-submissions/{participationId}\"","className":"PublicProgrammingSubmissionResource","line":77,"otherAnnotations":["@PostMapping(\"programming-submissions/{participationId}\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"testCaseChanged","httpMethodAnnotation":"PostMapping","URI":"\"programming-exercises/test-cases-changed/{exerciseId}\"","className":"PublicProgrammingSubmissionResource","line":143,"otherAnnotations":["@PostMapping(\"programming-exercises/test-cases-changed/{exerciseId}\")","@EnforceNothing"]}]},{"filePath":"PublicLtiResource","classRequestMapping":"","endpoints":[{"requestMapping":"","endpoint":"lti13LaunchRedirect","httpMethodAnnotation":"PostMapping","URI":"LTI13_LOGIN_REDIRECT_PROXY_PATH","className":"PublicLtiResource","line":52,"otherAnnotations":["@PostMapping({ LTI13_LOGIN_REDIRECT_PROXY_PATH, LTI13_DEEPLINK_REDIRECT_PATH })","@EnforceNothing"]},{"requestMapping":"","endpoint":"lti13LaunchRedirect","httpMethodAnnotation":"PostMapping","URI":"LTI13_DEEPLINK_REDIRECT_PATH","className":"PublicLtiResource","line":52,"otherAnnotations":["@PostMapping({ LTI13_LOGIN_REDIRECT_PROXY_PATH, LTI13_DEEPLINK_REDIRECT_PATH })","@EnforceNothing"]}]},{"filePath":"PublicOAuth2JWKSResource","classRequestMapping":"","endpoints":[{"requestMapping":"","endpoint":"getJwkSet","httpMethodAnnotation":"GetMapping","URI":"\".well-known/jwks.json\"","className":"PublicOAuth2JWKSResource","line":40,"otherAnnotations":["@GetMapping(\".well-known/jwks.json\")","@EnforceNothing","@ManualConfig"]}]},{"filePath":"PublicImprintResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getImprint","httpMethodAnnotation":"GetMapping","URI":"\"imprint\"","className":"PublicImprintResource","line":40,"otherAnnotations":["@GetMapping(\"imprint\")","@EnforceNothing"]}]},{"filePath":"PublicPrivacyStatementResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"getPrivacyStatement","httpMethodAnnotation":"GetMapping","URI":"\"privacy-statement\"","className":"PublicPrivacyStatementResource","line":40,"otherAnnotations":["@EnforceNothing","@GetMapping(\"privacy-statement\")"]}]},{"filePath":"PublicTimeResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"time","httpMethodAnnotation":"GetMapping","URI":"\"time\"","className":"PublicTimeResource","line":25,"otherAnnotations":["@GetMapping(\"time\")","@EnforceNothing"]}]},{"filePath":"PublicUserJwtResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"authorize","httpMethodAnnotation":"PostMapping","URI":"\"authenticate\"","className":"PublicUserJwtResource","line":70,"otherAnnotations":["@PostMapping(\"authenticate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"authorizeSAML2","httpMethodAnnotation":"PostMapping","URI":"\"saml2\"","className":"PublicUserJwtResource","line":104,"otherAnnotations":["@PostMapping(\"saml2\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"logout","httpMethodAnnotation":"PostMapping","URI":"\"logout\"","className":"PublicUserJwtResource","line":143,"otherAnnotations":["@PostMapping(\"logout\")","@EnforceNothing"]}]},{"filePath":"PublicAccountResource","classRequestMapping":"\"api/public/\"","endpoints":[{"requestMapping":"\"api/public/\"","endpoint":"registerAccount","httpMethodAnnotation":"PostMapping","URI":"\"register\"","className":"PublicAccountResource","line":83,"otherAnnotations":["@PostMapping(\"register\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"activateAccount","httpMethodAnnotation":"GetMapping","URI":"\"activate\"","className":"PublicAccountResource","line":115,"otherAnnotations":["@GetMapping(\"activate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"authenticatedLogin","httpMethodAnnotation":"GetMapping","URI":"\"authenticate\"","className":"PublicAccountResource","line":134,"otherAnnotations":["@GetMapping(\"authenticate\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"getAccount","httpMethodAnnotation":"GetMapping","URI":"\"account\"","className":"PublicAccountResource","line":147,"otherAnnotations":["@GetMapping(\"account\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"changeLanguageKey","httpMethodAnnotation":"PostMapping","URI":"\"account/change-language\"","className":"PublicAccountResource","line":180,"otherAnnotations":["@PostMapping(\"account/change-language\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"requestPasswordReset","httpMethodAnnotation":"PostMapping","URI":"\"account/reset-password/init\"","className":"PublicAccountResource","line":198,"otherAnnotations":["@PostMapping(\"account/reset-password/init\")","@EnforceNothing"]},{"requestMapping":"\"api/public/\"","endpoint":"finishPasswordReset","httpMethodAnnotation":"PostMapping","URI":"\"account/reset-password/finish\"","className":"PublicAccountResource","line":231,"otherAnnotations":["@PostMapping(\"account/reset-password/finish\")","@EnforceNothing"]}]},{"filePath":"DataExportResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"requestDataExport","httpMethodAnnotation":"PostMapping","URI":"\"data-exports\"","className":"DataExportResource","line":67,"otherAnnotations":["@PostMapping(\"data-exports\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"downloadDataExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/{dataExportId}\"","className":"DataExportResource","line":108,"otherAnnotations":["@GetMapping(\"data-exports/{dataExportId}\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canRequestExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/can-request\"","className":"DataExportResource","line":155,"otherAnnotations":["@GetMapping(\"data-exports/can-request\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canDownloadAnyExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/can-download\"","className":"DataExportResource","line":167,"otherAnnotations":["@GetMapping(\"data-exports/can-download\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"canDownloadSpecificExport","httpMethodAnnotation":"GetMapping","URI":"\"data-exports/{dataExportId}/can-download\"","className":"DataExportResource","line":179,"otherAnnotations":["@GetMapping(\"data-exports/{dataExportId}/can-download\")","@EnforceAtLeastStudent"]}]},{"filePath":"ResultResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"getResultsForExerciseWithPointsPerCriterion","httpMethodAnnotation":"GetMapping","URI":"\"exercises/{exerciseId}/results-with-points-per-criterion\"","className":"ResultResource","line":115,"otherAnnotations":["@GetMapping(\"exercises/{exerciseId}/results-with-points-per-criterion\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getResult","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/{resultId}\"","className":"ResultResource","line":140,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/{resultId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getResultDetails","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/{resultId}/details\"","className":"ResultResource","line":158,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/{resultId}/details\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getBuildJobIdsForResultsOfParticipation","httpMethodAnnotation":"GetMapping","URI":"\"participations/{participationId}/results/build-job-ids\"","className":"ResultResource","line":181,"otherAnnotations":["@GetMapping(\"participations/{participationId}/results/build-job-ids\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"deleteResult","httpMethodAnnotation":"DeleteMapping","URI":"\"participations/{participationId}/results/{resultId}\"","className":"ResultResource","line":202,"otherAnnotations":["@DeleteMapping(\"participations/{participationId}/results/{resultId}\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"createResultForExternalSubmission","httpMethodAnnotation":"PostMapping","URI":"\"exercises/{exerciseId}/external-submission-results\"","className":"ResultResource","line":221,"otherAnnotations":["@PostMapping(\"exercises/{exerciseId}/external-submission-results\")","@EnforceAtLeastInstructor"]}]},{"filePath":"GuidedTourSettingsResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"updateGuidedTourSettings","httpMethodAnnotation":"PutMapping","URI":"\"guided-tour-settings\"","className":"GuidedTourSettingsResource","line":46,"otherAnnotations":["@PutMapping(\"guided-tour-settings\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"deleteGuidedTourSetting","httpMethodAnnotation":"DeleteMapping","URI":"\"guided-tour-settings/{settingsKey}\"","className":"GuidedTourSettingsResource","line":60,"otherAnnotations":["@DeleteMapping(\"guided-tour-settings/{settingsKey}\")","@EnforceAtLeastStudent"]}]},{"filePath":"MetricsResource","classRequestMapping":"\"api/metrics/\"","endpoints":[{"requestMapping":"\"api/metrics/\"","endpoint":"getCourseMetricsForUser","httpMethodAnnotation":"GetMapping","URI":"\"course/{courseId}/student\"","className":"MetricsResource","line":41,"otherAnnotations":["@GetMapping(\"course/{courseId}/student\")","@EnforceAtLeastStudentInCourse"]}]},{"filePath":"ExamResource","classRequestMapping":"\"api/\"","endpoints":[{"requestMapping":"\"api/\"","endpoint":"createExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":218,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":248,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"updateExamWorkingTime","httpMethodAnnotation":"PatchMapping","URI":"\"courses/{courseId}/exams/{examId}/working-time\"","className":"ExamResource","line":313,"otherAnnotations":["@PatchMapping(\"courses/{courseId}/exams/{examId}/working-time\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"createExamAnnouncement","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/announcements\"","className":"ExamResource","line":348,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/announcements\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"importExamWithExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exam-import\"","className":"ExamResource","line":373,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exam-import\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllActiveExams","httpMethodAnnotation":"GetMapping","URI":"\"exams/active\"","className":"ExamResource","line":514,"otherAnnotations":["@GetMapping(\"exams/active\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExamsOnPage","httpMethodAnnotation":"GetMapping","URI":"\"exams\"","className":"ExamResource","line":530,"otherAnnotations":["@GetMapping(\"exams\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForImportWithExercises","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}\"","className":"ExamResource","line":543,"otherAnnotations":["@GetMapping(\"exams/{examId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}\"","className":"ExamResource","line":563,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getExamTitle","httpMethodAnnotation":"GetMapping","URI":"\"exams/{examId}/title\"","className":"ExamResource","line":612,"otherAnnotations":["@GetMapping(\"exams/{examId}/title\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"getExamStatistics","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/statistics\"","className":"ExamResource","line":626,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/statistics\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamScore","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/scores\"","className":"ExamResource","line":649,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/scores\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-for-assessment-dashboard\"","className":"ExamResource","line":667,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exam-for-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamForTestRunAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exam-for-test-run-assessment-dashboard\"","className":"ExamResource","line":704,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exam-for-test-run-assessment-dashboard\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getStatsForExamAssessmentDashboard","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/stats-for-exam-assessment-dashboard\"","className":"ExamResource","line":730,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/stats-for-exam-assessment-dashboard\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamsForCourse","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams\"","className":"ExamResource","line":747,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getExamsWithQuizExercisesForUser","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams-for-user\"","className":"ExamResource","line":765,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams-for-user\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"cleanup","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/cleanup\"","className":"ExamResource","line":788,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/cleanup\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"deleteExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}\"","className":"ExamResource","line":810,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"resetExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/reset\"","className":"ExamResource","line":834,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/reset\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addStudentToExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"ExamResource","line":858,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"generateStudentExams","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/generate-student-exams\"","className":"ExamResource","line":890,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/generate-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"generateMissingStudentExams","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/generate-missing-student-exams\"","className":"ExamResource","line":935,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/generate-missing-student-exams\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"evaluateQuizExercises","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/student-exams/evaluate-quiz-exercises\"","className":"ExamResource","line":966,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/student-exams/evaluate-quiz-exercises\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"addStudentsToExam","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/students\"","className":"ExamResource","line":999,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"registerCourseStudents","httpMethodAnnotation":"PostMapping","URI":"\"courses/{courseId}/exams/{examId}/register-course-students\"","className":"ExamResource","line":1017,"otherAnnotations":["@PostMapping(\"courses/{courseId}/exams/{examId}/register-course-students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeStudentFromExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\"","className":"ExamResource","line":1044,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/students/{studentLogin:\" + Constants.LOGIN_REGEX + \"}\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"removeAllStudentsFromExam","httpMethodAnnotation":"DeleteMapping","URI":"\"courses/{courseId}/exams/{examId}/students\"","className":"ExamResource","line":1077,"otherAnnotations":["@DeleteMapping(\"courses/{courseId}/exams/{examId}/students\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getOwnStudentExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/own-student-exam\"","className":"ExamResource","line":1105,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/own-student-exam\")","@EnforceAtLeastStudent"]},{"requestMapping":"\"api/\"","endpoint":"updateOrderOfExerciseGroups","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/exercise-groups-order\"","className":"ExamResource","line":1123,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/exercise-groups-order\")","@EnforceAtLeastEditor"]},{"requestMapping":"\"api/\"","endpoint":"getLatestIndividualEndDateOfExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/latest-end-date\"","className":"ExamResource","line":1162,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/latest-end-date\")","@EnforceAtLeastTutor"]},{"requestMapping":"\"api/\"","endpoint":"getLockedSubmissionsForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/lockedSubmissions\"","className":"ExamResource","line":1180,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/lockedSubmissions\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"archiveExam","httpMethodAnnotation":"PutMapping","URI":"\"courses/{courseId}/exams/{examId}/archive\"","className":"ExamResource","line":1206,"otherAnnotations":["@PutMapping(\"courses/{courseId}/exams/{examId}/archive\")","@EnforceAtLeastInstructor","@FeatureToggle(Feature.Exports)"]},{"requestMapping":"\"api/\"","endpoint":"downloadExamArchive","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/download-archive\"","className":"ExamResource","line":1235,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/download-archive\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllExercisesWithPotentialPlagiarismForExam","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/exercises-with-potential-plagiarism\"","className":"ExamResource","line":1268,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/exercises-with-potential-plagiarism\")","@EnforceAtLeastInstructor"]},{"requestMapping":"\"api/\"","endpoint":"getAllSuspiciousExamSessions","httpMethodAnnotation":"GetMapping","URI":"\"courses/{courseId}/exams/{examId}/suspicious-sessions\"","className":"ExamResource","line":1302,"otherAnnotations":["@GetMapping(\"courses/{courseId}/exams/{examId}/suspicious-sessions\")","@EnforceAtLeastInstructor"]}]}] \ No newline at end of file diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json index d55648326e00..3d697912c662 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package-lock.json @@ -9,12 +9,12 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@eslint/js": "^9.6.0", - "@types/eslint__js": "^8.42.3", - "@types/node": "20.14.08", - "eslint": "^8.57.0", - "typescript": "^5.5.3", - "typescript-eslint": "^7.15.0" + "@eslint/js": "9.9.0", + "@types/eslint__js": "8.42.3", + "@types/node": "22.4.2", + "eslint": "9.9", + "typescript": "5.5.4", + "typescript-eslint": "8.2.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -41,44 +41,38 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -86,45 +80,47 @@ "node": "*" } }, - "node_modules/@eslint/js": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", - "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -132,6 +128,26 @@ "node": "*" } }, + "node_modules/@eslint/js": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -145,12 +161,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -219,40 +242,42 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz", - "integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==", + "version": "22.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", + "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -261,26 +286,27 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -289,16 +315,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -306,26 +333,24 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -333,12 +358,13 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -346,13 +372,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -361,7 +388,7 @@ "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -374,55 +401,52 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -435,6 +459,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -444,6 +469,7 @@ "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", @@ -483,13 +509,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -505,6 +533,7 @@ "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" } @@ -514,6 +543,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -526,6 +556,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -612,6 +643,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -619,18 +651,6 @@ "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -644,41 +664,38 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", + "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -692,23 +709,32 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -726,15 +752,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -745,6 +762,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -758,17 +788,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -791,6 +835,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -812,6 +857,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -820,13 +866,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -843,6 +891,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -854,7 +903,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -872,15 +922,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -888,6 +939,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -912,51 +964,25 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "ISC" }, "node_modules/glob-parent": { "version": "6.0.2", @@ -970,38 +996,14 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1012,6 +1014,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -1031,7 +1034,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", @@ -1056,6 +1060,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1076,23 +1081,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1119,6 +1107,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1143,6 +1132,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1154,13 +1144,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -1173,6 +1165,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -1216,6 +1209,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1225,6 +1219,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -1238,6 +1233,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1260,15 +1256,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -1321,6 +1308,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -1337,15 +1325,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1360,6 +1339,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1369,6 +1349,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1390,6 +1371,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1419,6 +1401,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1433,22 +1416,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1473,10 +1440,11 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1510,6 +1478,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1531,6 +1500,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1561,6 +1531,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -1573,6 +1544,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -1592,23 +1564,12 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1618,25 +1579,23 @@ } }, "node_modules/typescript-eslint": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.15.0.tgz", - "integrity": "sha512-Ta40FhMXBCwHura4X4fncaCVkVcnJ9jnOq5+Lp4lN8F4DzHZtOwZdRvVBiNUGznUDHPwdGnrnwxmUOU2fFQqFA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.2.0.tgz", + "integrity": "sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "7.15.0", - "@typescript-eslint/parser": "7.15.0", - "@typescript-eslint/utils": "7.15.0" + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/utils": "8.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -1644,16 +1603,18 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -1682,12 +1643,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json index 2cf9dd7ba054..aa79b4aa50ae 100644 --- a/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json +++ b/supporting_scripts/analysis-of-endpoint-connections/src/main/typeScript/package.json @@ -6,14 +6,15 @@ "main": "AnalysisOfEndpointConnectionsClient.ts", "license": "MIT", "scripts": { - "start": "node -r esm AnalysisOfEndpointConnectionsClient.ts" + "start": "node -r esm AnalysisOfEndpointConnectionsClient.ts", + "update": "ncu -i --format group" }, "devDependencies": { - "@eslint/js": "9.8.0", + "@eslint/js": "9.9.0", "@types/eslint__js": "8.42.3", - "@types/node": "22.1.0", - "eslint": "9.8", + "@types/node": "22.4.2", + "eslint": "9.9", "typescript": "5.5.4", - "typescript-eslint": "8.0.0" + "typescript-eslint": "8.2.0" } } From 4dc60a8c54b7b21ff85e32bfd15002161de622e6 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Wed, 21 Aug 2024 14:39:18 +0300 Subject: [PATCH 11/60] Development: Update gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradlew | 7 +++++-- gradlew.bat | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 zcmY+pRa6|n(lttO3GVLh?(Xh3xVuAe26uONcL=V5;I6?T_zdn2`Oi5I_gl9gx~lft zRjVKRp?B~8Wyrx5$mS3|py!Njy{0Wt4i%@s8v88pK z6fPNA45)|*9+*w5kcg$o)}2g}%JfXe6l9ig4T8ia3Hlw#3f^fAKW63%<~GZJd-0YA z9YjleCs~#Y?V+`#nr+49hhsr$K$k!lg}AZDw@>2j=f7t~5IW6#K|lAX7|^N}lJ)I!km`nrwx> z))1Es16__aXGVzQM0EC8xH+O!nqTFBg9Ci{NwRK*CP<6s`Gq(~#lqb(zOlh6ZDBK* zr$|NDj^s6VanrKa+QC;5>twePaexqRI%RO~OY075y?NN90I|f^(P# zF=b>fZ73b5JzD`#GC3lTQ_B3lMeBWgQUGYnFw*HQC}^z{$6G4j(n4y-pRxPT(d2Wgb%vCH(?+t&Pj z)QM`zc`U`+<~D+9E{4Uj2kc#*6eZMU$4Oj6QMfA^K!rbl`iBix=2sPrs7j@aqIrE zTaZJ2M09>rp$mgyUZ!r2$UK{+DGqgl`n;*qFF~M(r#eh`T{MO?2&j?xgr8FU$u3-` zhRDc_I23LL4)K&xg$^&l-W=!Jp-P(_Ie07q>Je;QLxi8LaEc%;WIacJD_T69egF?7 z;I_Sg_!+qrur8$Hq4grigaiVF>U7uWJ@Hkd&%kmFnQN-P^fq0gB1|uRt!U#X;DnlV zo?yHWTw7g5B;#xxY`adhi4yZn@f(7-Xa(J6S=#d@&rlFw!qfvholE>MEb|VWn^g}G zMSrK&zQ^vDId&ojL!{%{o7?s{7;{+u%L{|tar(gp?Uxq3p?xAysB>0E$eG#$tvkk9 z2Q2gEP17{U6@UD*v({5MP-CTZfvWMItVjb4c;i~WLq&{?Q1(koX&vt7+$z}10{^Id z{KDjGi0JpD7@;~odF__0m|p;5rIrHidOP9^mwKe#-&JX-X@acc)06G{LO1Wu)#gvZ za~y9(fhA%UwkDOVU1LBJ`0ROE z4&)dJKK%mG@+CIm?+wt9f~@xIMr8}UH*K1j| z0pppo{7gv3v{URwxVMeg>Ps!L5IKxm zjac2egjgb0vH5i75$s|sY_RYec#>faqJk|AGgV;v=^%BM(^p{p;(^SVt-88G9f!q; z>p}9E4^f0=01S2pQBE4}9YqE%TV)*hlU^8k9{&=K76+*Ax^r=AkBb%OCP^P2nm0Ri z;D-|Zk?gGeU<12ti2CnPVNA(Pb)02+r|&yTWW-OJO7 zNLb0pps6aN?A~NJp5kj{{IOlf!5KWMleV@-hYLift)D>-7K+tgs=7Ake}oBnIy-y1 z(Hn@Hjw=_(x>dO5ysQsrnE%A*bk0K<-j{1Yqz@#n#jOL^AzCr#wR|WYzqk6i7v)Lf zkXdKxzuu20aP{Tbg$(+9&oh7cd(Uoqqf<#ujb$q4sZ~gxFbQfS zS)kNklyL*{2AELgjZ(LBu*>S(oH5AaJ;YiB@;l@=O%F6B?oanzoYRM^fQ9-<~^=3$H0g^JPMLQo@SZ@QuNvy)tyJ)LSj`+()#fy?{aV4Yg^7dlQ7AQM^3GLCR2dAFR zJjtfKiVqF`l-H_fz0HD|9g>)pOxn}k!vdZ=DO!7Sikm{Z%P6BrRkBS6W?ZB5W&7rT z@uYpf@M@a!z7H&o@-yrcCL^Ff3e7p3T`R9p?@o-acXmbTSa0>ZANzCSgovsd%;i$| zVus`not!oL#(W`L-!9w0jdaECaG4hk{V7IOs676ZquZH~0TX5hDq|)x z6T497l|E?f4)LA>j=S8}b$0LS=I4h|hUFJYJODT8Li@#6kF$k0)@*l{RnM1HQ%?VT ze-Pqlc!~t(oumVC*?5fwR;P6u{tHaZ~*LlD;B)4f? z?lpWfa2P@)g57flVl83Ej%P`2)gGyaPjhvD(%i~{`2b>#3!+y&` z!2nuwHMFA-zUY}f1^0B8<`N)Gr=A4TS@b1qykmd0Pq{?r)+1^^+D(=xasb^Tf!oK9 zBLL+*p6M_#ufgLzgq1zcSwZsZnQWFLC3`Yxdg-2=*tT`J9nrfYt)RF)YryBf8_gW{ zvKbB+oZLehfT)S#<|y1)E0hW^?+AnqPXq9Hu;v3dsMGdr{SVyF63;K<8VcgI#~}1i zLYSBL0K;RTT(;>2x=*!1Di9w0mwr;`CN}kM65|Ay{~z}_^JKOsRaN<~#9O^iiW<5P zYN7r~HV!#Nz~IZU`P>1Xe%4f~K}KcF#X&5kO*G}-)74S*tQ8CietdPcA1Yl;S=Mr# z`#MYY!{s^uo=jn7;k6O%(}fN+*0cWMpt~#n9DR<3NyU?+3D^AgI}S)Cu-Tljg`VY} zX1=fq$?8$DtOeGxE6f8lbS_6Q3C4+LDTO$}_IpM$Xv<|QSC%+Oll^q$y`7o@jD{dp zNDl|&X)r7wETa-#h*d`KXntxI(Y{vLha{$0i7@G8xx^m=c<{lJ9?p-i!^W{%j7-oo z0W^SzZ^(Wkyz*We{lEn%Yhu-ycUOHtrRiVJL4~&S91*D0MrLu}Q>v-Mc?GcWfpyz% zX|UvcN@krFO#@v|CtYM}g|=L3%aMo$E5<@CM%c*;?u>LOTz00@+dt1{yg1y=$h+{|D17U}$*^fE^H&8b431EUE z<9tv0V_#%#&1N#j7AKCj!tTK@J%oFW*ESW<(#Gl#Xs%v<@AitI?s92nLzm<)w3Wkkom1f$gcdUi%g_*jofy&}N#luL<$GVIe{iQkQ)sIHVy zBgItnPBFamrv6Kb{eE($Q(f`ZPeW!Hm%Y@F*OF1sKB{Yy|C>WEv_mfvv-N-jh)B-5 z4a!1WcT@9a+hGaBrc~sz=>G?Q!*Zp^JFRUvBMyNR1;`)j$RhH$6gEyVKhd$&K-CFT zXaWC-Y=fyOnqT84iMn9o5oLEOI(_3fk!W^8-74|q1QhQ|CmT0i=b;6Z3u?E{p7V{? z;f#Q-33!L+4&QQcZ~GAqu$NS{M;u%`+#9=7^Oa5PKvCCCWNG_~l(CidS!+xr-*gg{ z$UQ`_1tLT_9jB=Hckkwu>G{s0b0F4bnR7GibmHo?>TR&<3?D;5Fb#gd8*wYa$$~ar z7epl1qM)L{kwiNjQk}?)CFpNTd?0wAOUZ|gC{Ub|c-7h~+Rm(JbdoRe!RNVBQi!M8 z+~U6E2X&KSA*T6KJvsqwqZl#1&==Dm(#b^&VAKQ>7ygv*Fyr;)q9*^F@dCTg2g!w~ z%hg)UXAUyIpIbLXJv1nZX+a_C)BOH2hUim|>=JHCRf(!dtTidb&*~I!JrfRe+PO>w z@ox$G2a3i9d_N9J=|2$y2m-P&#PTNwe!oLBZFs;z|F5kXvBDn<)WwE0E3$ow=zg3R zK(9;sf0t;VEV3@gAg7jRtnj%-6O@!Hvg*;XcUAw}!=2*aErvB(eQIm(-UGmq^J=XN zTqJo$Y|WKo^HlBF3BXJrA#}7ZLg=r*w`I*~Ix`o&2k8^(0mt8Rp=A>F`&gehhp@Jy z^e^#B2!~$LvNCKugg)8)-G%&THdk~kfextilegP9?#C#()F59U$&eo(h|5>ceo*Em z{PEE79T$YP|Kr7K`WBHbtQwyxFkCl6xX&+oUf90B5xoi3_5KHHCyEE*oPbOQkfMz& z6^hT8_NXd2iWk{q9IKae1{_7hMPH8I7_BMtVOM4 z6jm?E0QJOn$qrgsJ`9w##GB9?G})-GXSQo6(tYS(Q0-Ct$co?Zzl0?NHsDRron?;_ zZZgQg)%XW>P?8_&zoGuF(>Och2kEJXsu1_X&~w87x!b z>~h!a>e7{`p@+#hXF88wI*JeWRZ;J4ev4<}HWf|Z;(7$E!S5l9wzBHFe>^I{2`a;a)QnAwa2xv1e(bq$<}!8o^ofGvYpk7dBR+`*%iE;hUY5 zaHF}OjGO9r*{%lmcK^uFiTHgoUD`^9Nx@~;Bg!V* zuuJ&ti{DQiq7RyJAR94wem{}cPK1J(Yxnn_{=>?USqz-~&QXRStS^s-7TksZ$AEI! z#og36s3JGtGU{CnDHRFtipFqvrE*gw7_K@NN0h+ItTq@4fqN!HeQU1y7*X?9+IfZT4Vxebpt z%#VzgdDK~-&+=Z*#>=n#XUhNvBZp3=Cr41jMqwJkHLf3L7Vm~V#GgJ(Jpii~PmJ#s zA7Ft!{xD@z>9DUb4JbiUBdNEcU4BO$651iN*mp*f)HbRRM`Cx5cR?5IfEcU{IZWwf zz(M6CDv)>xa3x}K6%tP^i15P1&&DOLK=k~+jNR$UK3frSl+|PjSC-dBItvD~LL! z>_g(YYdO4k(5EbPOw+v+;G7~jYm>F@Ai|o`gs%F)F8tDz$dl7Q%aCe|v|$UkAul_R zNlA-beBX^IJU?kgS`E$it7nF4DaI!SJAGq)2P&Few(-|tp z?K+%D3e4{pfkayrcbm0ftu6Ol2ZzdKM+4i!hNP3NRL`EvvZJ3yvNr2MV%igZ4kj``Qrdb_OI$7jWP z;l0DYf&0(-*QcP5zrP`HVznW+SbH63Qx$7_9~NjRNg7eKqI!UJ=XH`g^=t8GiFTu( z?2L{JKEu%jJx&XjNzU(*!ZNmL1@RlJA0G$2_LrAb_7lmjil(GSlSM zwTes`m+3R;3#N~Xg#9owh3ycXV8@ZlaY_16kpPFA={721b~URO4HD3sp%fmkZM}k) zZB0#)kP=RkNB~R-MCk8aljG_bagt4vIb~8)BV%(b8_;)&Kf9GX+%O_cNG|(D$!3&D zL(I8}*LqN5NntipFlN13=`D>6!{D@CFMBH0kW3=HccJV+xW~|$qeFR5i-2{X+iWMu zI2$gepQ)H_B%ip_BlWOQ*|pErXs|4ir{IHccgaIJ84irE{?+$KDABXr&f`jB^V-c% z$$u`uU1YB^{<+UN2cNg#7&0bz@yF?5>j|;)5&IV3wIQp58X#OE-M^$HdyvL|Um5t? zhZlAG!Mz%XkUe3t471JM*Yur}o30vzu6RN7gJyNcf!IItsDO730mcJ*O!~V``y5=3 zNJGp34DZ}wd1H6V`Uuy%es>BiO_aE-S8jzir#$& zyk)@2a5tP$@g%jW^b^JGdo)X@Q%sE`^lDQmY9m%uDFpPX`w9%=yQ+nneMm#OaXcD` z9}{tn5A2b2z9783vL2_jSao?uxJhWJoq%47*RafM4o0@gY(p)F>qT4^XM5GLzV#6j zC+HoGhAne7o_w{WUo(B++z7lU3Y0k1rYv9|TSv0vR-Du(5=VakbbelgZTeDn+a_Wv zq_j-^+Qz1WAl;Zg>ahX|CERbX1V%B!hTKN?M}fGoA07M(WU&NfT&TmN`P@56U2 z^)vLDs|Ln~0iTtn-?KTeQl@T&bskJFuTUS!m+$CS9vnd}8(UMO|Kv6TCfGN9NUu&4 zL{)GTxPq>fwsJ~aU=4Qhuq8*RzDsP(LZh$BHezq&9gK$IS<|DYbm})$QTGCS6T;Dr zEkLct!b+#<1r9OKG@P!f1wm8>=Nz!7OzJm!g<+`?N3;YaA3(P@EL=(sTaRMDD!c8=-XN^4BXp(eVkj$NmEMYPP>YJ4bJ3yUud z<3BeJAJ$6z^TuywnfH5lv#$lgwraNw{IV=tIznPH1DT`v-5yS=!)J<}xxl}uZf9azA2A97Haf!;<3y01hlw?dWNEv@TLi1s-mO4vmIT%O_42nS z$VRWrs9NngqRRkWAnWkn%`Rw@?wH|)7XL`EL5EZu$qyJW31&CB^T_)qwIv!{;E_6 zo-9XAryQRlk-O0>o#-SZO>|6OYq;}<*>Wu1AsVRiXY4f8qb;+sItv3AyS!4Ry+q}) zA!pAB|BmC;=RIOk^^vlsEH(!Q!7_1FK~ZB2err*o!+b(r=m1b?$6d!%zmN+69LXnT z&gRmM+n_R-F@sT*IYv0_mGPvur!u`iWbQO7SqiGFLeY&yga zf`lM&B74FA2C?N@8_z652fjhBEoDUKbP8hL{0{HAF%qDo7)o3=3rg#6)T7%%5^wl% z9R0*S*<~>nzYOdQk2l`9h#t+gJy_xujw6xjV(8S<_DbVg61&pT%Hi42l%D73G?adn znB%UdNM0p}lEF-P2%TAMam2zpQev71e>a$$%i+r~b+D9G9pF|oY_*(-u*89oKsXLY+UIbqq)MQ%(GYS{(*n_S_*RN$*~`zUtab%0aKwhx znc)Yo?{xq1sJCgQD)TeTci1ucvbez9q=A72H(-SB18Kl&6^vHV8^i!p@>iF!DIw17 z+8Q)TNisB7>pwyww4y)yJx*wX6SJO78eLBC-ar1+k$Z9fy;wBD|3kzI{<+l*>PSY^ z_?nLOZaeWbU@C3hfK?X;Di*8CHCPkx2qco6(ZyJdqSzp^TJ_5Lpa0UP{Gy+!b0Lr% z@xYxSjUKoY6L#>$qx~KD$-0=|OF7zhVP~ntMgEALYPIfhj@+ z!;JJ7te>CcovruwHsJH6Lta$nm|%^C@=V-rmhU{+I~0(|XHQ9jt@L7pb{gx#{4r!) zg($FyFTslcgu(~6lYr$nW?)%*l#VJ=R-jxK(x=t1bWlu(nL66T#qj%3aZ@uVhy}Co zDU_q61DD5FqqJ*#c|(M5tV)XBN?Ac^12*q)VN4yKPJ|#==S_`_QD9|0ls!`2)SwuHDRA_OfXQDq3%qW&MZB}Z!=k-9xqev8jHz(H z{^D@cIB~QiK>~wa)A&^Ll^Wi6QgCzU;iv-BHsLBs zH7=jN%|>0S`SjP%M&AF1PNVDp_FZ?2Bm@7`DC&v(pYrw!!yD#4 z6+<=HS0Ln6MhoKxF<%~H`y20{vf#pxh=;j{zY381gvAFekgG|>G1zo8$&az{V=;JR zy_puF4$L$?EMhT?;TpQoR*j16ll`#AS4e96C}yp_aGKkBe?1H|k_;gG-~Xorc<;lI zkB}fB{$c-D2mGA&{rm<*@F5)c3X+6??g~XoEwuzSuch0D@W~P5(2I8v8F$c2$Vw51 zP#YLSBDqtWW^EYBl^QYHF+MA7am6f4DOhwnJM=W9$uvMOsZ%_~?)2C#wb?CkI$7{K zEi)=#|5pFvg^){zK5kpBLjB2kZ+$ZB|L=W|aNwyyb(gC2l7bcpx{E-H@)q6@D6N^xh`{1E%ItF2$eeB_SjI@b2WgTpS1thwg&n`jiIzw^TtXUyB{00($GIq>vbj|}bav}}Q_~wp3>k8!E@hVC;OMUTu|= zAy#vXH*GrUHu7^cNZWe1>y;2(51js9wbu+R3Aa*(wzH9+X0dIsf&gc_x|_LP z>~CF^?(~U}+l~ehe|i>?4eo!xkq&Lk+RR-1duNP#o~>@1x)s&i&u zRaYL@+D&_M|JLI6fHbEr_`U;HgPTh#E3?sB)A$*gqyBgg*ql|a-m*TX5rACbWKCE6 zdeQ`v8m6>g^ugv`p|HY^#1QZrGGUj0^HVDc@{?Q0yhalbBEV{+|HzC^-{&e{5K%z9 z6Bxtnfu1!@Mp+Q&*&~;FOg&*Vm<@4b;{FG0-!UUXX!|)1w}op!B_|7_s~d(+=9Gba zKp8`LaB4D(H=cGcspJ_TjYaOwMb=sGn^gtUVhK!UI~2KKYEE-NC}F>+BEY7IVvy%KRvm00tg!Q`y=er}wpEetX}K@;}(}{s9AzV#q2@ zBy7}->|N?13POrs`;U?(qAG(I$~Gt+Rgw%aNZ_0fs_utVvRJT-7z4!@x36v@=NBX=IqkK{#Kg0w48de@?#Yb4M(Svj5=T+<ONr8-oh7l?Cji@+erqur zFhZ=9|Lk=$`c}v4u`)-!!UI=!9Jo@h&7p4RlS#u! zZ7-prn75JkV?VjptX;@$#`U`{vB!=Z?V`T*FBF>J?vsML7e6@2GbUteMFfX-TUu{2 zLNIG*;dV)8GV8gAgEf#)X3A>p3^CRka1v?~8x^anBhQ=L=LsOl=&pcOYHo98m##ye z34MtGCDK!`ptl?taGMr5q{!zVc? zG00e){TV?`YA9eB;(lA3lXI?RrB4BYQGk?vOmTIUJED=(`_*gtn2DB-t4WW54as*W zb2kD-lWX>lb$+W!VFakki>B^Vc+u$?NLF>)!U%b@Y}gYJ>m2H=^x0=nsE0TF^Yu0h ztgH8-o1%+jCk(+&`|)tTfEVHq0cMeFa{Uz)X$;fCq%Y=SOWML6bYfeP8j5hktL`KK z(18`XrUn&WN9PtFxh&dX`y~YBsmdhi7Kw%tKzM%^VEhdD<_XkulW-x=JN6OPbFI4@ zzDDRN+f=@{0h*MswwOqG6gJ?{NuHx(y-|FUGsxyZ*x0~$MW(eY>vqq4Fh#t7uzw=- zKB?|!0N~!h^AMdLa)oR!Ca#HZ9&Zf)ghuO<^RN)4twRlygHnQG(BE{cDc5E}OF4;xss6gYyV~EcJvJkX)xNWb=@yw!uq0v-sf^rvkp-;?DPWK@*SEw|V;IH=7 zfQqEV_>DjOPT~8X*J|H8=&RnzK4~S7ML~nLX^%s-Vqc^aWy7N$y57qciZGcqy#=zU zs8hcHiI=D$+RB{|62{ohCTiaML6FI4Uhzo5D{Jik@poCs0w7F)*w}F4r0sJ~#u-72 z5bK=ANt=M$Dh5NKnxGsg9NRR?WD-x|FhTwBjd zD<-K>44DB~i%frJOfnzh1R>PRY34kw!6~p3M$JLaD1r@`=h)~Ngks-(gdXh^Q?BTP zZ^Zj5w1AwtuR2$~E7s9iZdF}z%pv1em^V2rM{1tLUY@-+Sc0(9jA|iZWml1;v13=U zHf?y@#mb--7z6$ue>`qjhE~brk$AY-RG90~5wcBbDReXR2)pKg{L>;H(DI`U!MLNQ zY9rFJP@ZQ}jlcMh%WSCo%vf+nd0Gmd*F%KMIe>slCUh)8Ma|;M_I+v#;|ueg9oLg; zq2HtZX%&#F7vdpNlkX?}(C7dGC^y#NB#m4%69RzTNrk%4ol~hSI%>2r6B|*ZkW(*P z;u#s;+faHo{tfy+1L^RzWDi*^JR0iY(zJDB36y_QJ+|E-2x+cY z!V8uLNktH~q>WQZuY!Ap66WP|E!0PA1jK~)^8oJVGbspJs6QL!!-5Qm7 zHYI|_`Actg?vDzdg5{86w@GS$G6ANzff7->6i5pB$T4O}`fZ_;{217Om0gN5zTr12 z5mW{hCzCE-QubjxN$TAE-XgI-8dTY@OZmq`y+y_>dk*(qXF0{nam|q@~i}Utp*k{yurq(DW54hkDT4bbg z=_etM?Nf5W^o-HEu9_?&xEqPg^P^mTxLH8n%u$!mWvFG|{&)jtnU&6|5-`~eaNz0%D1BDo`{ zS1N5(KW5v^2eLdd_%`uaRndF@h0Uo6=M|8?b~KbOLZk{HXEnGmtgZXf2inI*1r%n! zQ3&%RI4r{f&dwW~HwH0Ked9b!k6{>_19H z_Ai>5IChDMY(FfMyG%;30?SQ{iV9KyGru62+Y)~qSQ91}b~}w<&*}R&1c#$O`H@~c z5)2S_eXx}M#N{MuGeQS9@#UJB@;W_j50b}jIhxMPloEFQZdvwxiU^RYycTzgK)-vl3LT&$L8~@68$C8~5_U{cR$E#w*x65(qw&eoL@>%ZHvj zWnEMlSh*(o&oy|J7eJ5OD`ssy%F?*Vp?`Cq;FShyl{ZoKCG5g{y}>usznni#8ki(i zO{w@n{iAj1_ooX@+s*!uW60WcH~*bNOT6z%0jVML5};wVrQp~`Uss_{cO2oud_nNA8^B$?07fJ6?iI)Q zuo9G)O-z)DqstrBqf>B%S05hf-wep0@$BFHKSrkZ{za3D)yVzRz)2{wf8(Wp+xyAM z$rtyx$gi3A=V~V!`Q3;BM0$>*VVtxEM|xDL^gew7ydy3Q6YzD&THRz*q33Ms_D;M- zbCx1Ft#UNB)V3bf`~{ImI72OTp^|bF8?G8#FRj+Biy8ET5#rA3sd|0FR@U(LAJ%w8 zS1%n8Z=Amhw)92rIsof=YVWF4jw&F*j1LG@-`+cR0-~2LqXRH8(Ccne{y#MCPncF64U`0uO zWmi$dlii~1D0rLR{qc|_2M!C$t8^=G7xQY)9!#Y331A|>N)EhmyVdLWL9I3YLJ`7? zZmpqUJB>Ni9oiL)^1IK1UoMyhWE{$9M2M6Xi zPKk7GpMsA6vjZbU7~i+u|J6Nk|Ci!Y3UMUT2|`M;JsNQACdJ%ooo9Yt{?A+0hMpxi znEa~~sxC>rKrU6bd=WRb;%wsH>A#j4{({&1GYSNR57Gama(3)2A;SM>qop}l>Jk2* zn1+C$fIxuwzg3mCU#SOqb-wOCb6mBcYlA5+mt<&_J~sBxc(GQtBFINUO~Mr7<-uu($>P HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ zF^}Ea+#Je`Xy6;#D0FPnSrR%Y!QGA~NA^{oWmW8C<3dr{x6wWQ{4+bzemqV5W$i5~ z=J0jXZ>uZb>DT@0Ks?4QJ{`z?8JWl3$y;2pj#$XP*pv$>$g(z43{YH9KmmR6<#sIn zA`#=0#sgycaBQ^&}Xba!|KaZ8~b30v~nLt z9%#gz_*=~KD{3t^X~l>480*}PhKN=??g`RV|4Ud{Gyyl187MJ}r(#e+H$GEdI+p1s zq_25h;fV)$EPK%Dw-(G=f`yHB-_tttsC!?k7*#!|4a>`Ahj8nm?&n>NRs%jkZW^3-0P_yMP5&*6a26{MRj1&TPF zyE#|c)5uUHzMWx=rMKpuPih*V=S;W3MzIZTw2uTbr}8`p2bm+Z6Sa%vvWAWSf4H)p(+ zSQ8;EvUa#wqWV+9vmIio(%7wukK2SwjUS8Yl%Rq%=~PU)2$Tvm6`1!r3H@U#_|bB0 zmlT1PS3wPB(b&^+@YY7Y$n4l3mV3-X0$>z|gZp6O*Lhzn&?Gad2ZCF;+#95-Y?#y+ z?*l@Yf=a4w{Px=o!N|3~_XKfk&G;fN>Ps&dp2FpA~qD=0~=!NOS@B#XAKKkND>Y{4>rqxrViKD7;?>j8`R` z&G)3FN|dfsxnaI^!d1G%=>AbTTxZWo;n-DLrQ!sj=f~VAOe5zhGS(dgx|!ls62fbX zV@<7Ck^!}R=`Swr?(7w1rY6Nmq~sfXJ?TiKJLn=&SQdEt9$@0 zA+h1Wbwbri0s-stc8yVq;mRa6@kEf8^KXUz&jcic!+avDvvJFa>k0ioWug=T3oPw; zyj4it&0@>_*uI@2=^+T7sL1_!^aJW@Xfo8aC#3^WtQC7fET8b9C} z*u^ue6Ojn z7@(eskJ2+cNnH9~VyfIh<-|7!je~vGy*odz(sk-u$~SrYF3glruZ*W`{sqnS+9=;Z zh{D@MSG91%lr&ua8%$sJF%y1I<|e;EdfJykY8#D$Hc_81n5`$7;1N|b0tvvPLzSg& zn7!5x?T*@rQUKcUhTIjV(rw*5oQYlm5DbEO?60#mohHfbR$3_x#+PZoYi@Vd4`#YgKyTd^!4n{fN~WZDY61sAOm6 zl!d^i*a01QxpWM9Pcl?&{RgO}uq%ErOk5WpECvnfEh!*YP&1Sl)uTN4hg??Vqs~i5 zYsfufz3?{TtwuBN=`0~Qg1PlWH#OGG$ zLLWU17$v``)CE1cds_7kj8mJ{-+l8{DS|zAQ&3|qpOY=!J|kXUhXue9|H>4gqk|n) z-i34GmxLFj8asb3D#D&=ya*a5`C<=o?G;Ev^LV%;l#nH#O=7Nh@z1Do>j6Q;I5S2P zhg|AZbC&|c7}uSJt57s2IK#rSWuararn-02dkptTjo*R{c5o(bWV}_k3BBnKcE|6l zrHl&ezUyw^DmaMdDFVn<8ZY=7_{u{uW&*F<7Al6};lD(u;SB=RpIwI)PTyL=e25h* zGi{lRT}snjbMK~IUx|EGonH+w;iC2Ws)x>=5_{5$m?K z5(*1jMn%u0V1Y%m@`YS3kskt~`1p(rA4uk;Cs!w^KL$w>MH)+cP6|XKr4FfHIATJH z!EGAK4N>1yFR`-zW|w%ByRe#=&kA&#WyUldDGpt!wf-8SFWiSi!5QZL+l7*CE?u!NW1T$<1rdLJ9y3u{_zvHaM?#Rm4 zFk}^1!ffcrB|XK3gsO-s=wr*sUe&^$yN|KxrA)uW00Gu60%pw_+DcUjW`oW<35OC8 zq2{j8SgC}W$?10pvFU83(SL$%C?Kctu3*cs0aa%q!fjn1%xD*Jrm!F3HGR9-C{b?- zHp(cL;ezXMpL@0-1v0DMWddSDNZ5h?q50cOZyVi#bU3&PWE=(hpVn|M4_KYG5h9LffKNRsfhr^=SYiKg?#r&HNMi2@cd4aYL9lw(5_IvQJ zcB*DD()hUSAD^PdA0y|QrVnqwgI@pUXZXjHq3lG2OU&7sPOxxU$Y3&ytj6Qb=2#cC z;{d-{k|xI*bu+Vy&N+}{i(+1me!M;nshY_*&ZQLTGG*xNw#{RpI`3^eGfHck+*38NRgiGahkFethtVY=czJs#)VVc{T65rhU#3Vf?X)8f0)X{w!J3J{z|Sq|%?)nA+zo?$>L9@o`Kc|*7sJo4UjIqu0Ir~S5k^vEH};6K?-dZ0h*m%-1L zf!VC%YbM1~sZOG5zu&Sh>R;(md*_)kGHP)<;OA44W?y53PI%{&@MEN}9TOiqu+1a3AGetBr$c)Ao3OX>iGxmA;^^_alwS818r4Pn&uYe^;z6dh z)68T|AN=hjNdGpF7n>y+RTAZc9&opTXf zqWfK_dUv=mW{p_vN>|(cIkd(+Jy}qnK{IW%X*3!l`^H~FbAHwof+vLZ0C2ZXN1$v7 zgN&R9c8IO`fkR{6U%ERq8FN<1DQYbAN0-pH7EfcA{A&nhT!Be>jj>J!bNRw4NF|}! z1c70_#fkk!VQ!q1h2ff@`yDyrI1`np>*e#D4-Z~*!T^8#o*$V~!8bWQaie?P@KGBb z8rXc!YDL!$3ZgZZ%;-%~0Kn<+d+{xJ$stQbtN8GWV?MCJvzPU|(E(1z;rFw{&6vy) z3*@y%7Tx8rH-p$boS>bLyod?OKRE8v`QSBvGfY6f}_{Zo1q85xoyOF16n~yHx2W ziydUoYLkJmzq|n&2S(O!ZmLdP1(o1Jsq88cX)x3V-BK5eF&0e_0G!5?U7&3KN0`mc zH&Lt)q8!d_VgzxyL^(@xrbp2y)Hmr^V48));RSfE=*Ly0uh9!$3dv-vMZr2URf@l5zdwLjGZB zugY>7_fd_vbV*Qv1?H~>Z%RD%nEeFSI$n$$Lrpc6g>i4+XdBB!%zM$Bhrz5Swzyg? z$~I~n@~-wTBY3-T&pr+|gC+OHDoR?I(eLWa{Z#Rsh>lc~%u0!&R|s0pA*w<7QZ}{i z*AFr~0F3y~f$MGh_HDL7J_1?SxKL}fWIk!$G}`^{)xh*dZ5kK>xGL9>V`WZZg_ z)^Vm)EQK`yfh5KiR(vb&aHvhich z_5o+{d~0+4BEBqYJXyXBIEb1UgVDs;a!N2$9WA>CbfrWryqT25)S4E4)QXBd*3jN} z?phkAt`1rKW?xoLzEm!*IfkH|P>BtECVr0l8-IGk_`UjE#IWkUGqvyS+dMrCnFl<7RCgSMX^qn|Ld_4iYRldO zY&cHhv)GDo8nKvKwAbfyLR%t?9gG?R7~PSD#4D-;?F&!kV59O}neYut5AGbKwy-(U zqyBi=&Mgj|VIo>$u!DHM`R7O?W8-idbePuxiJMH``6c_5L-chKd}=rGC5Gfrc{f!* zWFEBm?l@_b7kzY7%1RQQbG5V<4=ZlkZ%sF74Q|mKOc7Ak7dP2#quiGcZ0_J%7Q?j{ zv9{WFw;n5G-Mn%r#0R;{jLt{yy}9J6rQ(>X9pJ`7Xy?Zv z=lNit#qXaq?CnElK^zF~sG}U5oCpR0T>FH=ZX}Prju$);?;VOhFH8L3I><9P_A|C+ z{;>~dk%9rrq(snjsEm}oUz2FQ21MCG*e?g)?{!&|eg7PX@I+Q0!hL6C7ZVY|g2E>i zr!Ri2@OfEu$)d52+>+cpgh6Z;cLYCZ&EMR0i<^~4&wEu_bdo;y^6}+U2GIQgW$|Od z_jg{O=pU>0-H$P-EOlWyQy#W0r@@_uT}Lg+!d5NxMii7aT1=|qm6BRaWOf{Pws54v zTu=}LR!V(JzI07>QR;;px0+zq=(s+XH-0~rVbmGp8<)7G+Jf)UYs<$Dd>-K+4}CsD zS}KYLmkbRvjwBO3PB%2@j(vOpm)!JABH_E7X^f#V-bzifSaKtE)|QrczC1$sC<<*Y z$hY*3E10fYk`2W09gM_U<2>+r^+ro$Bqh-O7uSa)cfPE_<#^O) zF+5V;-8LaCLKdIh3UB@idQZL`0Vx8`OE#6*1<;8(zi&E7MWB1S%~HAm%axyIHN2vd zA(pJGm_PraB0Aat3~?obWBs?iSc*NhM!{-l_WNCx4@F7I?)5&oI|z{o@JKd1HZ}zf*#}JjK3$ z-;3V*WJZvUcKvSOBH4c7C{fl8oRw8-vfgKQjNiR|KhQ%k6hWNEke(k8w-Ro| z7Y3)FsY-?7%;VT64vRM)l0%&HI~BXkSAOV#F3Bf#|3QLZM%6C{paqLTb3MU-_)`{R zRdfVQ)uX90VCa3ja$8m;cdtxQ*(tNjIfVb%#TCJWeH?o4RY#LWpyZBJHR| z6G-!4W5O^Z8U}e5GfZ!_M{B``ve{r0Z#CXV0x@~X#Pc;}{{ClY_uw^=wWurj0RKnoFzeY` z;gS!PCLCo*c}-hLc?C&wv&>P1hH75=p#;D3{Q8UZ0ctX!b)_@Ur=WCMEuz>pTs$@s z#7bIutL9Pm2FDb~d+H}uBI#pu6R}T{nzpz9U0XLb9lu@=9bTY&PEyFwhHHtXFX~6C zrcg|qqTk(|MIM%KQ<@j=DOjt|V)+8K26wE_CBNnZTg+Z+s}AU|jp6CFoIptG1{J*# z7Ne~l;ba*=bSwAMQ|Vq#fW~+je4PXA91YFzBubNF?ovIOw-$C-8=Ehed{lGD0}(Id zRe4sh8L>&T%{>8o))he}eE;5_ zxoXk3wX?MyNl-xF!q1d$G?=wp^`@09(jU&X zOqZIBI#dN`2PJNdATR3ivtub|nO$dulSaP|e4)WXF1YAGN1pDQIbIjXFG!oC85Mt; zW$eteoL{y^5t4TMRwP$jNPjZFpGsWnGe=jMMqKtcZm9Y9PFZLi*1p@qoKKub^T@2+ zk$@*KYdQ?Z`}<%4ALwk*Yc{(WTf@#u;as(fvE^9{Gk)lWbJP*SjttWofV0s?AB({~l zZI1hZVWFT~W-T?nfMMcnCS4-#6H-MU7H$KxD;yaM46K4Kc@~Q>xzB+QnD_I`b_l3m zo9pRx46b!p?a^&zCDwygqqV3epjs(s0NQI6ARA1n!Yy-qduipxQ& zUAlqRpNjBS+y-ZheD(!R;F}&^V_}b_gqH%tVZ5%%ziO7k^w=es+wZtK^i*vmrWNLMs{oWu_CIov|s1raZiS)>38>pYu;i+-t zI_DiNe6aA4KTZ2P09qPj(0~K4nUq^0+f(2$g`229zkG4jLzRvJUWE0oF1XHL4t3UN zDH466G56sy9hTZoAJB!C3;@F;ONxEk5u6Mv%zdo}Rq`=* zw1n7MOhfNSV48TS989ArIcj`C%Gk8~93~u>)!Yt2b4ZriKj9x2d`H2HQNJ=I>hkDlcZn zqRj>!;oRMTIOu zx|Zfsu~v76T{z7AC(jxj^c@tnJHZtGPsq$DE!8kqvkDx5W?KUJPL+!Ffpwfa+|5z5 zKPCiOPqZZrAG;2%OH0T$W|`C@C*!Z`@Wkop{CTjB&Tk`+{XPnt`ND`Haz;xV`H^RS zyXYtw@WlqTvToi;=mq1<-|IQ(gcOpU%)b#_46|IuWL#4$oYLbqwuk6=Q@xZaJSKVF zZcHs~ZBl;&lF3=+nK; zF`4gSCeZXlwmC_t4I`#PUNQ*)Uv&oGxMALip|sxv^lyVV73tKI7)+QY5=tEMas{vTD-BaTJ^*Y6gq~PU;F5X!sxqiq$iFCo+Uv7m%1w((=e}Vf*=dtds|6 zbX}91!G?C*KG03eHoN}RZS9DJxa&8YwNCT8?JxMXyZqZr13NA|GB{+vG`08C{V(yy zf*Lw$+tYSU_+dI`3n{bMrPdDb`A=Mkg!O=k>1|*3MC8j~- zXL79J4E=U^H=iBLTeHE_OKzE&dws8RNynsSJ!d;`zK?P92U{f)xvD7VQVosrXZrL+ z6lMVdD1YgL;%(1cq{#bS6yXmp|DS@nax#AqqlZhtUQdh<^2vr5`EpAO

LGYq)sa(w9^3-f}NHy=GR4v%t2YZly3m1G@5y`xBh_HGrD%f z>;|Ty?9FiJAc&UVD(StT4I` zfVQwxhE9bXE6r2mKO8Ag7{L^jCyqQb0QqKDPE=RAgqn8q1O^>(z7h5kE(6va%QqRZ zkIOmp(})rLSS(2{=C12e&@!W2=Jel-^_R``0xHO^+t!(oXbcv5yhD4g*$t_F)_5Dl zSVCgesW%;DtYPCFs{G;GX_o?1J3;QQPPv)rWw;>} zJ&KwnUqwNXloNXlK_+pNDfI~hON#SokVJb&ilg8d7^NWo2ZQymCqQMnjfi>ePibjr z-Z@q!?RGN$Mj}Nk){X_vaj6?Mj$>ACR*z|6MsXy3VZ^PFn@yHkPo(>m(iWepn8SC@ z>D2;R4m+gDRZ=SIX!b+CP(qE=JDIUkn=D$aUu+Ihn9-+k1LS3PreQg0N5eWIG@x${nC3v^7caS>1!PKNAY9J z#}E}Q9w#SP>(GY7Hbj&z4$Li6o5taBO|4+F`yS9zq*LJ<38wy4I>HA9(&GYrk4dLajKGww))BWli6Ln1A^Lda@N~p+snkb9C z@OthI+<##vp8!HVQT4Wk(=@zQ{OvZ$EKWS73+JHb)eYLGD-cqi6^|vd$<+IHuc?Nq zW7JertT~3))4?J|28n$I@nAD0c1%9C&IVhEZX~mUsf{efyS(XNG%ch;!N~d7S(Ri7 zb&=BuON95aVA&kLn6&MVU|x}xPMp7xwWxNU1wS+F6#y}1@^wQZB*(&ecT?RnQcI}Y z2*z!^!D?gDUhc@;M^OpLs4mq>C&p{}OWVv<)S9KMars@0JQ{c_ScGsFo3BJ)Irg++ zAWwypJdTO-_{Uh8m(Z!3KL7K{ZZzKHj;{M8I$mV>k znTM?sa0);^=X^cglL`uC+^J)M7nEa$w=VwFULg~%DJllw+7dJAj3{qnP5i3@wr7%y zjXp?Wl2%Th=my&3u?Q$RV6N5tzKMSPTsc#J+-cDDp~qFB6bL2C8AS7Y3PKtVhdhl) zIaLqH5+OnWPWSt(lQCgkN8lczc-V%_iZ{>#1%Z$N*>lu#S;0MZ$T2Y8Kg!U;hAZj> z6S#%$DQ_`Ic%Zr@?}GgjRXg@qTj^17n`65oJ@Wj0u1X8&+UVd|Xs?J+i_^GZ94m6= zUc96~Q`OJvlKB_Lr15*Yw_PUPEr?f?H&00b^-W%26mD)(n(rGGNfK9~2h=C>p-7BZ zFd&*&Msdu{w~(eyFOglwCPH^Rb}O(N7LtS+nnEwDx*pGD?|&9Si~M43a+*L(b0$5A zv`T`(G3xO;I_sx;FwTP21ZlfDpz zOo?}Vlgf~fo{YWm@n_JyD*frOg{XsvBA~|Tn4V6hu>Gd>89-rblfVJUaGvj6X%NZ} z$tFF9sx=4_$*c~G`9iPLGh@=sV+O{D2-t*K@J7H=`V+oVt}8?04WwU3h1BgS!f%1P zFak-T#7`TtLcR=Yz>g0R!ZQrH!YiZOQN=_V-UyncN1Rc18?KY?#O`v#JK+pq0K$~H z3D@v9DZF42R)b9#BBX{^$DOMlJ!g)Gc za{o-1e%F6NvgKq9tC8pV+9S$;9*zNv{J*)n&dmf~anP1)4~N%~h#c(=B#3*KgzhCKhFdgDoWi2IDog{RVyzK|Y`rCUs3T~pJMmdZJy4?b z&s5G=zhf**(t7Y^oC_mcTsE-{^}wiaoUu&?kojLKs>SJPxjcP>{a5CbXCx92AcBE) zHtqP}LjZ{W>PH?Tu(E0X=%{PBMW@F_?#7b&#!^q`<-5$ur+-q6 z{dn=(^UZw6*3-XM_(=@<1_*i&XM4=0t5u!gm6 z{UlmNGPKgO_;e;q9|#esq~Sq`<}%d{+sRmhvsA{5i*91=tub>OZZ%)xUA#4q$dDyy z1`w4%?OPLg3JeZb#cqSMO?*Xn%|-FCcuH2i2fn_{IFusub6;NQdN|7TD1N?%E8*g? z$apAt@cEe!I%jB=*q$p_3=t_5R0ph%{qaq+QDg!c99Y!Xa!&oDZOeis_ot)gNXr{l zdY$|So2Qed2Y7KMNBrS^E169kG%h<+z{Z_p_;shB!uY)>yAVcK=&!bg`lVg)4T1|7 z0}7FpfydVH4F87K@c!nEG+WGKm{Ouo)Slpl;#qcEIQ0zdMfLA#;dBxYw;p;KoVv6| z3_D5&7rJdG12CnDSvZUW?$UC6^UVSW^|vw|o-_4bz)(w5(3AiVhpeT(|=f#x_}E?s#qHZF#xA6AF_ujl$G z-jHD%q(d2}v2PhXx&6YWps~m(^+RXl91Q#xRRJBhjKl$FG4bk);|ag;ieUZ&!Ii3$ z(iGz1+0m7#g5>ASldBbNZL=ZHh=tmmJt$!71; zIML2GhEz1pg@1rQN(M^_691wAGkJ@Pga_05WuQ6! zG5RkGY2^`@(H~pp7&Ga+Pwh3L!Njj!-rc;^bTIfo5hP@H##1X8xUZJckrx>id`bAd3QUx9GuomqBYZ!uN1-&o zvTxC?;p8vL67&fW8fw(YOqt>L@bdLrEF*3OgYe$4n4{ zEB40LiU#6-0@5jdN`0w}N0qi@c0~oT2FP z)LNk&a82my?jv(tQpiMi$TK_L@lub#lsM$R{Dk?Ya@%%%huZkct~tSWM714c!45k}-ZLVA-bVM`>|_ZBbW_m-7| z3U%xrAhi}n?T(2F{_n4EZ10inkIFl#y09?7$uwBoJgqY8vylwev)fDOn;>0R!aEnV zBz%j0Mqpx~EZU3q@%+oV7;}|vt7$~ou@faEIq{p?FY$XXg&6*K)b_LP=}gi9`Bij3 zN`zEo|B6*|-;>S`rNa^BKRDbDAk>X#MsR`EvL>6bqU@SaDDs z8>bu@3YdRaWs*Te@G-UHjU%F~kTHw5(0PVJ+pwh#ha2u;DB+UMo@A5UYIl#5rtBV- zGX_hIpw}3C@H*Us(Cc-d#-gNrG#w$(9+S=GxO>3SR`SE2fHZ2KrDc#_C^$jI>Y}#; zMwY=R6@+dWi~0RXw(c@3GZ&%~9K(q&ee0Zw;pwL`E_tZak-#8^_b)Dpyi73^he?xV zXJ08&wh5-M&}qy4f7!D&=E)puDD(Nmg1d_(j`4LvxM5x_huNg-pGG%9rYqO6mImyJ@}*3Y>^3OvcnTG%EV1) zq_Ap?Z!Iw__7#D=pOWnQN$gB!Mr0!9yx|g<4icJh{cFOu3B8}&RiYm+Mb;VEK``LK zL(NcpcTiGieOIssSjr?ob}^``nNf&UcJhXyncO9m{6gD$kqSD`S69(aF8dkWz5>!9 zBLe4Sib7Hs2x_L2Ls6Ish$MGVKrGt5+_2zCyP1byaCg3upo+-I}R4&$m)8 zQ7|jc1Z^VWggpuQj*cP;>Zo9LS!VSzrqmZczaf;u`d0J(f%Z9r%An@s!e>n9%y=n!IZ_tVGu{Jmsbp}Fk%HJIU?a+-~bjfLTuH|JExA8EROowzr zqW9{YyZhR0a4clRK>1I4Ncx&WER~{iE;F^$T7K%X@3PGOA%6#Z%p3TS^&M;Dnjw@i z^o!$9nhcsmcHcY4?4j9+ofL_CWsZ4Hcch(rjsGfGD(nsH>w}^ERqGnz%iGj0j{g}h z7wMkJ-2Z2~eS>2!i}0~B63i;>SyFJU2+>VCS^AxaDOx%g6-t0eM^P<3+*z`ztvOqrG3)&#$K?& z_Y0wbWID47@cU`E1A6A&!`aZk0ZE@z-h#l1NqX2#`$Uev2gepW`rf8*!=rD5&;Jb{ zl08rU>dPo=K%-1Ao1~G-@4ve~y5#9E8x;TE0k5d^TC(=Zc>mwjW^c=+U-<9}b0ku~}gj z3sbW>R2M6DR!g#NUP;nxo>)@7*=RP{U18SDop6b2&PHce^&h97@xx3t+VK+!keE#} z;(Uf&89as9k8{$nkLbuB!-d7TP`_VJpL^Xs8OKB~ri$YUbW8fch64}7|0EWoT(TRj{ z*GT<7Y<7DsrCi79ZsM)z#c(!nNOGySOCkY1fAuQOq12&iUVC!a`#O;dBLf=d?&4*B zI~LgAO7E0qxK(uRTM;IgJ}+z^gD+bi-6I!3x{r9`l~%8TRP%UE0V8E*Sz>Nl1NVG<<7(wDHZ+HcOkQm$O&k+vyx)y)x{Pz!U8hS$*m zByc0h6BUI*BOpuL==P+H|Hx%`>7!W+1H!l9vi&)`V zyn2o9{z=lc+VX*!Vh~SF=)L}Z40XeG>LF6cP^b+R$NxSeUqbK^Q*UTalKzP8X%{9@RSCXm_NhF>{=S2 zi}ezam_^P`S!!-cyEW9y7DBbK93roz@Raccy*v}?mKXScU9E_4g;hBU7}zSofAFda zKYEe?{{I54 diff --git a/gradlew b/gradlew index 1aa94a426907..f5feea6d6b11 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30dbdeee..9d21a21834d5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From d5d999f93646a76837432b4928aa620bac2e32ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20G=C3=B6=C3=9Fmann?= Date: Fri, 23 Aug 2024 18:04:35 +0200 Subject: [PATCH 12/60] Development: Tune data export test to prevent flakyness (#9155) --- .../artemis/science/ScienceUtilService.java | 18 ++++++------------ .../DataExportCreationServiceTest.java | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/test/java/de/tum/in/www1/artemis/science/ScienceUtilService.java b/src/test/java/de/tum/in/www1/artemis/science/ScienceUtilService.java index bcbdb17eafb0..d7cbc1010b9e 100644 --- a/src/test/java/de/tum/in/www1/artemis/science/ScienceUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/science/ScienceUtilService.java @@ -23,11 +23,12 @@ public class ScienceUtilService { * @param identity The login of the user associated with the event. * @param type The type of the event. * @param resourceId The id of the resource associated with the event. + * @param timestamp The timestamp of the event. */ - public ScienceEvent createScienceEvent(String identity, ScienceEventType type, Long resourceId) { + public ScienceEvent createScienceEvent(String identity, ScienceEventType type, Long resourceId, ZonedDateTime timestamp) { ScienceEvent event = new ScienceEvent(); event.setIdentity(identity); - event.setTimestamp(ZonedDateTime.now()); + event.setTimestamp(timestamp); event.setType(type); event.setResourceId(resourceId); return scienceEventRepository.save(event); @@ -39,14 +40,7 @@ public ScienceEvent createScienceEvent(String identity, ScienceEventType type, L */ public static Comparator scienceEventComparator = Comparator.comparing(ScienceEvent::getResourceId).thenComparing(ScienceEvent::getType) .thenComparing((ScienceEvent e1, ScienceEvent e2) -> { - - Duration d = Duration.between(e1.getTimestamp(), e2.getTimestamp()); - if (d.toNanos() > 500) { - return 1; - } - else if (d.toNanos() < -500) { - return -1; - } - return 0; - }); + Duration duration = Duration.between(e1.getTimestamp(), e2.getTimestamp()); + return Math.abs(duration.toNanos()) < 1e5 ? 0 : duration.isNegative() ? -1 : 1; + }).thenComparing(ScienceEvent::getIdentity); } diff --git a/src/test/java/de/tum/in/www1/artemis/service/DataExportCreationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/DataExportCreationServiceTest.java index e21e7563d52a..98f8b97e07e3 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/DataExportCreationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/DataExportCreationServiceTest.java @@ -167,7 +167,8 @@ void initTestCase() throws IOException { apollonRequestMockProvider.enableMockingOfRequests(); - // mock apollon conversion 8 times, because the last test includes 8 modeling exercises, because each test adds modeling exercises + // mock apollon conversion 8 times, because the last test includes 8 modeling + // exercises, because each test adds modeling exercises for (int i = 0; i < 8; i++) { mockApollonConversion(); } @@ -230,7 +231,6 @@ private void assertCommunicationDataCsvFile(Path courseDirPath) { /** * Asserts the content of the science events CSV file. * Allows for a 500ns difference between the timestamps due to the reimport from the csv export. - * Might cause the test to be flaky if multiple events are created overlapping and matched wrongly. * * @param extractedZipDirPath The path to the extracted zip directory * @param events The set of science events to compare with the content of the CSV file @@ -249,13 +249,13 @@ private void assertScienceEventsCSVFile(Path extractedZipDirPath, Set createScienceEvents(String userLogin) { - return Set.of(scienceUtilService.createScienceEvent(userLogin, ScienceEventType.EXERCISE__OPEN, 1L), - scienceUtilService.createScienceEvent(userLogin, ScienceEventType.LECTURE__OPEN, 2L), - scienceUtilService.createScienceEvent(userLogin, ScienceEventType.LECTURE__OPEN_UNIT, 3L)); + + ZonedDateTime timestamp = ZonedDateTime.now(); + // Rounding timestamp due to rounding during export + timestamp = timestamp.withNano(timestamp.getNano() - timestamp.getNano() % 10000); + return Set.of(scienceUtilService.createScienceEvent(userLogin, ScienceEventType.EXERCISE__OPEN, 1L, timestamp), + scienceUtilService.createScienceEvent(userLogin, ScienceEventType.LECTURE__OPEN, 2L, timestamp.plusMinutes(1)), + scienceUtilService.createScienceEvent(userLogin, ScienceEventType.LECTURE__OPEN_UNIT, 3L, timestamp.plusSeconds(30))); } @@ -635,7 +639,8 @@ void testDataExportContainsDataAboutCourseStudentUnenrolled() throws Exception { var course = prepareCourseDataForDataExportCreation(assessmentDueDateInTheFuture, courseShortName); conversationUtilService.addOneMessageForUserInCourse(TEST_PREFIX + "student1", course, "only one post"); var dataExport = initDataExport(); - // by setting the course groups to a different value we simulate unenrollment because the user is no longer part of the user group and hence, the course. + // by setting the course groups to a different value, we simulate unenrollment + // because the user is no longer part of the user group and hence, the course. courseUtilService.updateCourseGroups("abc", course, ""); dataExportCreationService.createDataExport(dataExport); var dataExportFromDb = dataExportRepository.findByIdElseThrow(dataExport.getId()); From 0748077da9ec1619cdef0cda98f30ba5f6ae1a69 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sat, 24 Aug 2024 00:30:40 +0300 Subject: [PATCH 13/60] Development: Add performance guidelines and integrated them into the PR template --- .github/PULL_REQUEST_TEMPLATE.md | 13 +- docs/.readthedocs.yaml | 2 +- docs/README.md | 4 +- docs/dev/guidelines.rst | 1 + docs/dev/guidelines/database.rst | 8 +- docs/dev/guidelines/performance.rst | 219 ++++++++++++++++++++++++++++ docs/dev/guidelines/server.rst | 8 +- docs/requirements.txt | 4 +- 8 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 docs/dev/guidelines/performance.rst diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8cd968c38187..7e405ef32689 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,8 @@ #### Server -- [ ] **Important**: I implemented the changes with a very good performance and prevented too many (unnecessary) database calls. +- [ ] **Important**: I implemented the changes with a [very good performance](https://docs.artemis.cit.tum.de/dev/guidelines/performance/) and prevented too many (unnecessary) and too complex database calls. +- [ ] I **strictly** followed the principle of **data economy** for all database calls. - [ ] I **strictly** followed the [server coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/server/). - [ ] I added multiple integration tests (Spring) related to the features (with a high test coverage). - [ ] I added pre-authorization annotations according to the [guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/server/#rest-endpoint-best-practices-for-authorization) and checked the course groups for all new REST Calls (security). @@ -21,7 +22,8 @@ #### Client -- [ ] **Important**: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data. +- [ ] **Important**: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging). +- [ ] I **strictly** followed the principle of **data economy** for all client-server REST calls. - [ ] I **strictly** followed the [client coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/client/). - [ ] Following the [theming guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/client-design/), I specified colors only in the theming variable files and checked that the changes look consistent in both the light and the dark theme. - [ ] I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the [test guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/client-tests/). @@ -92,8 +94,8 @@ Prerequisites: #### Performance Review -- [ ] I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance -- [ ] I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance +- [ ] I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students. +- [ ] I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students. #### Code Review - [ ] Code Review 1 - [ ] Code Review 2 @@ -103,6 +105,9 @@ Prerequisites: #### Exam Mode Test - [ ] Test 1 - [ ] Test 2 +#### Performance Tests +- [ ] Test 1 +- [ ] Test 2 ### Test Coverage diff --git a/docs/.readthedocs.yaml b/docs/.readthedocs.yaml index 9522486c382b..4e14204d7703 100644 --- a/docs/.readthedocs.yaml +++ b/docs/.readthedocs.yaml @@ -4,7 +4,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.10" + python: "3.12" sphinx: fail_on_warning: true python: diff --git a/docs/README.md b/docs/README.md index aaf6ac4ae190..a806a39d5ef5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -60,11 +60,11 @@ RtD will build and deploy changes automatically. You can install Sphinx using `pip` or choose a system-wide installation instead. When using pip, consider using [Python virtual environments]. ```bash -pip install -r requirements.txt +pip install -r requirements.txt --break-system-packages ``` or ```bash -pip3 install -r requirements.txt +pip3 install -r requirements.txt --break-system-packages ``` The [Installing Sphinx] documentation explains more install options. For macOS, it is recommended to install it using homebrew: diff --git a/docs/dev/guidelines.rst b/docs/dev/guidelines.rst index b53f26746d0d..8574b339f28d 100644 --- a/docs/dev/guidelines.rst +++ b/docs/dev/guidelines.rst @@ -7,6 +7,7 @@ Coding and design guidelines :includehidden: :maxdepth: 3 + guidelines/performance guidelines/server guidelines/server-tests guidelines/client diff --git a/docs/dev/guidelines/database.rst b/docs/dev/guidelines/database.rst index 7898ab2caa33..0c7119159a9d 100644 --- a/docs/dev/guidelines/database.rst +++ b/docs/dev/guidelines/database.rst @@ -1,8 +1,6 @@ -********************** -Database Relationships -********************** - -WORK IN PROGRESS +******** +Database +******** 1. Retrieving and Building Objects ================================== diff --git a/docs/dev/guidelines/performance.rst b/docs/dev/guidelines/performance.rst new file mode 100644 index 000000000000..192f3dc34739 --- /dev/null +++ b/docs/dev/guidelines/performance.rst @@ -0,0 +1,219 @@ +*********** +Performance +*********** + +These guidelines focus on optimizing the performance of Spring Boot applications using Hibernate, with an emphasis on data economy, large-scale testing, paging, and general SQL database best practices. You can find more best practices in the `Database Guidelines `_ section. + +1. Data Economy +=============== + +**Database-Level Filtering** + +Ensure that all filtering is done at the database level rather than in memory. This approach minimizes data transfer to the application and reduces memory usage. + +Example: + +.. code-block:: java + + @Query(""" + SELECT e + FROM Exercise e + WHERE e.course.id = :courseId + AND e.releaseDate >= :releaseDate + """) + List findExercisesByCourseAndReleaseDate(@Param("courseId") Long courseId, @Param("releaseDate") ZonedDateTime releaseDate); + +**Projections and DTOs** + +When only a subset of fields is needed, use projections or Data Transfer Objects (DTOs) instead of fetching entire entities. This reduces the amount of data loaded and improves query performance. + +Example: + +.. code-block:: java + + @Query(""" + SELECT new com.example.dto.ExerciseDTO(e.id, e.title) + FROM Exercise e + WHERE e.course.id = :courseId + AND e.releaseDate >= :releaseDate + """) + List findExerciseDTOsByCourseAndReleaseDate(@Param("courseId") Long courseId, @Param("releaseDate") ZonedDateTime releaseDate); + +2. Large Scale Testing +======================= + +**Test with Realistic Data Loads** + +Given that courses can have up to 2,000 students, simulate this scale during testing to identify potential performance bottlenecks when handling large amounts of data. + +**Benchmarking** + +Perform load testing to ensure that the application can handle the expected volume of data efficiently. + +Example: + +Use tools like JMeter or Gatling to simulate concurrent users and large datasets. + +3. Paging +========= + +**Implement Paging for Large Results** + +For queries that return large datasets, implement pagination to avoid loading too much data into memory at once. + +Example: + +.. code-block:: java + + Page findByCourseId(Long courseId, Pageable pageable); + +**Caution with Collection Fetching and Pagination** + +Avoid combining `LEFT JOIN FETCH` with pagination, as this can cause performance issues or even fail due to the Cartesian Product problem. + +Example: + +Instead of: + +.. code-block:: java + + @Query(""" + SELECT c + FROM Course c + LEFT JOIN FETCH c.exercises + WHERE c.id = :courseId + """) + Page findCourseWithExercises(@Param("courseId") Long courseId, Pageable pageable); + +Do: + +.. code-block:: java + + @Query(""" + SELECT c + FROM Course c + WHERE c.id = :courseId + """) + Course findCourseById(@Param("courseId") Long courseId); + + // Fetch exercises in a separate query if needed + @Query(""" + SELECT e + FROM Exercise e + WHERE e.course.id = :courseId + """) + List findExercisesByCourseId(@Param("courseId") Long courseId); + +You can find out more on https://vladmihalcea.com/hibernate-query-fail-on-pagination-over-collection-fetch + +4. Avoiding the N+1 Issue +========================= + +**Eager Fetching and Left Join Fetch** + +The N+1 query issue occurs when lazy-loaded collections cause multiple queries to be executed — one for the parent entity and additional queries for each related entity. To avoid this issue, consider using eager fetching or `JOIN FETCH` for collections that are critical to performance. + +Example: + +.. code-block:: java + + @Query(""" + SELECT e + FROM Exercise e + JOIN FETCH e.submissions + WHERE e.course.id = :courseId + """) + List findExercisesWithSubmissions(@Param("courseId") Long courseId); + +In this example, the query fetches exercises along with their submissions in a single query, avoiding the N+1 problem. Be cautious, however, as fetching too many collections eagerly can lead to performance degradation due to large result sets. + + +5. Optimal Use of Left Join Fetch +================================= + +**Balance Between Queries** + +While reducing the number of queries by using `LEFT JOIN FETCH` is often beneficial, overusing this strategy can lead to performance issues, especially when fetching multiple `OneToMany` relationships. As a best practice, avoid fetching more than three `OneToMany` collections in a single query. + +Example: + +.. code-block:: java + + @Query(""" + SELECT c + FROM Course c + LEFT JOIN FETCH c.exercises e + LEFT JOIN FETCH e.participations + WHERE c.id = :courseId + """) + Course findCourseWithExercisesAndParticipations(@Param("courseId") Long courseId); + +This query efficiently fetches a course with its exercises and their submissions. However, if more collections are added to the fetch, consider splitting the query into multiple parts to prevent large result sets and excessive memory usage. + +**Selective Fetching** + +Use lazy loading by default, and override with `JOIN FETCH` only when necessary for performance-critical queries. This approach minimizes the risk of performance degradation due to large query results. + +Example: + +.. code-block:: java + + @Entity + public class Exercise { + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "exercise") + private List participations; + + // Other fields and methods + } + +By default, participations are lazily loaded. When you need to fetch them, use a specific `JOIN FETCH` query only in performance-sensitive situations. Alternatively, consider using ``@EntityGraph`` to define fetch plans for specific queries. + +6. General SQL Database Best Practices +====================================== + +**Indexing** + +Indexes are critical for query performance, especially on columns that are frequently used in `WHERE` clauses, `JOIN` conditions, or are sorted. Ensure that all key fields, such as `releaseDate` and `courseId`, are properly indexed. + +Example: + +Create an index on the `releaseDate` column to speed up queries filtering exercises by date: + +.. code-block:: sql + + CREATE INDEX idx_exercise_release_date ON exercise(release_date); + +**Normalization vs. Denormalization** + +While normalization reduces data redundancy, it can lead to complex queries with multiple joins. In scenarios where read performance is critical, consider denormalizing certain tables to reduce the number of joins. However, always balance this against potential issues such as data inconsistency and increased storage requirements. + +**Use of Foreign Keys** + +Maintain foreign key constraints to enforce data integrity. However, be aware of the potential performance impact on insert, update, and delete operations in high-load scenarios. Proper indexing can help mitigate these effects. + +Example: + +.. code-block:: sql + + ALTER TABLE submission ADD CONSTRAINT fk_exercise FOREIGN KEY (exercise_id) REFERENCES exercise(id); + +This foreign key ensures that submissions are always linked to a valid exercise, maintaining data integrity. + +**Query Optimization** + +Regularly review and optimize SQL queries to ensure they are performing efficiently. Use tools like `EXPLAIN` to analyze query execution plans and make adjustments where necessary. + +Example: + +.. code-block:: sql + + EXPLAIN SELECT * FROM exercise WHERE course_id = 1 AND release_date > '2024-01-01'; + +Use the `EXPLAIN` output to identify slow-running queries and optimize them by adding indexes, rewriting queries, or adjusting table structures. + +**Avoid Transactions** + +Transactions are generally very slow and should be avoided when possible. + +By following these best practices, you can build Spring Boot applications with Hibernate that are optimized for performance, even under the demands of large-scale data processing. diff --git a/docs/dev/guidelines/server.rst b/docs/dev/guidelines/server.rst index 9e5a8ce068de..a4e510f362b0 100644 --- a/docs/dev/guidelines/server.rst +++ b/docs/dev/guidelines/server.rst @@ -99,7 +99,7 @@ Avoid code duplication. If we cannot reuse a method elsewhere, then the method i 8. Comments =========== -Only write comments for complicated algorithms, to help other developers better understand them. We should only add a comment, if our code is not self-explanatory. +Always add JavaDoc and inline comments to help other developers better understand the code and the rationale behind it. ChatGPT can be a great help. It can generate comments for you, but you should always check them and adjust them to your needs. Prefer more extensive comments and documentation and avoid useless and non sense documentation. Comments should always be in English. 9. Utility ========== @@ -121,10 +121,10 @@ It gets activated when a particular jar file is detected on the classpath. The s * RestControllers should be stateless. * RestControllers are by default singletons. -* RestControllers should not execute business logic but rely on delegation. -* RestControllers should deal with the HTTP layer of the application. +* RestControllers should not execute business logic but rely on delegation to ``@Service`` classes. +* RestControllers should deal with the HTTP layer of the application, handle access control, input data validation, output data cleanup (if necessary) and error handling. * RestControllers should be oriented around a use-case/business-capability. -* RestControllers should return DTOs that are as small as possible +* RestControllers must always return DTOs that are as small as possible (please focus on data economy to improve performance and follow data privacy principles). Route naming conventions: diff --git a/docs/requirements.txt b/docs/requirements.txt index 980c9ef308b6..d7f6f239f035 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -Sphinx==7.2.6 +Sphinx==7.4.7 sphinx-rtd-theme==2.0.0 -sphinx-autobuild==2024.2.4 +sphinx-autobuild==2024.04.16 sphinxcontrib-bibtex==2.6.2 From 5929e7fc0a813901de548e6422ccebd2085d4573 Mon Sep 17 00:00:00 2001 From: Patrik Zander <38403547+pzdr7@users.noreply.github.com> Date: Sat, 24 Aug 2024 17:48:33 +0200 Subject: [PATCH 14/60] General: Replace the remaining markdown editors with Monaco (#9230) --- .../legal-document-update.component.html | 15 +- .../legal/legal-document-update.component.ts | 39 +-- .../knowledge-area-edit.component.html | 2 +- ...tandardized-competency-edit.component.html | 2 +- ...ardized-competency-management.component.ts | 11 +- .../course/competencies/competency.module.ts | 2 + ...mmon-course-competency-form.component.html | 2 +- ...common-course-competency-form.component.ts | 12 +- ...tency-recommendation-detail.component.html | 2 +- .../course/manage/course-management.module.ts | 2 + .../manage/course-update.component.html | 4 +- .../tutorial-groups-management.module.ts | 3 + .../tutorial-group-form.component.html | 2 +- ...e-announcement-create-modal.component.html | 7 +- ...ive-announcement-create-modal.component.ts | 23 +- .../manage/exams/exam-update.component.html | 8 +- ...file-upload-exercise-update.component.html | 10 +- .../file-upload-exercise-update.component.ts | 9 +- .../modeling-exercise-update.component.html | 10 +- .../modeling-exercise-update.component.ts | 9 +- ...ercise-editable-instruction.component.html | 2 + ...drag-and-drop-question-edit.component.html | 15 +- .../drag-and-drop-question-edit.component.ts | 34 +-- ...ltiple-choice-question-edit.component.html | 17 +- ...multiple-choice-question-edit.component.ts | 64 ++-- ...te-multiple-choice-question.component.html | 31 +- ...uate-multiple-choice-question.component.ts | 2 + .../short-answer-question-edit.component.html | 1 + .../exercise-hint-update.component.html | 11 +- .../manage/exercise-hint-update.component.ts | 8 +- .../exercise-hint/manage/exercise-hint.scss | 5 - ...rading-instructions-details.component.html | 37 ++- ...rading-instructions-details.component.scss | 4 - .../grading-instructions-details.component.ts | 289 ++++++++---------- .../text-exercise-update.component.html | 10 +- .../text-exercise-update.component.ts | 11 +- .../text-unit-form.component.html | 8 +- .../app/lecture/lecture-update.component.html | 7 +- .../app/lecture/lecture-update.component.ts | 6 +- .../lecture-wizard-title.component.html | 2 +- .../lecture-wizard-title.component.ts | 6 +- .../markdown-editor.component.scss | 2 +- .../markdown-editor.component.ts | 2 +- .../markdown-editor-monaco.component.html | 35 ++- .../markdown-editor-monaco.component.scss | 4 +- .../markdown-editor-monaco.component.ts | 123 ++++++-- .../monaco/markdown-editor-parsing.helper.ts | 61 ++++ .../posting-markdown-editor.component.html | 2 + .../monaco-exercise-reference.action.ts | 4 + .../monaco-grading-credits.action.ts | 20 ++ .../monaco-grading-criterion.action.ts | 22 ++ .../monaco-grading-description.action.ts | 20 ++ .../monaco-grading-feedback.action.ts | 20 ++ .../monaco-grading-instruction.action.ts | 35 +++ .../monaco-grading-scale.action.ts | 20 ++ .../monaco-grading-usage-count.action.ts | 20 ++ .../actions/monaco-editor-action.model.ts | 28 +- .../monaco-editor-domain-action.model.ts | 33 +- .../model/actions/monaco-formula.action.ts | 6 +- .../model/actions/monaco-task.action.ts | 9 +- .../model/actions/monaco-test-case.action.ts | 4 + ...o-correct-multiple-choice-answer.action.ts | 20 ++ .../quiz/monaco-quiz-explanation.action.ts | 20 ++ .../actions/quiz/monaco-quiz-hint.action.ts | 20 ++ ...aco-wrong-multiple-choice-answer.action.ts | 20 ++ .../monaco-editor-option-preset.model.ts | 6 +- .../monaco-editor-option.helper.ts | 39 ++- .../monaco-editor/monaco-editor.component.ts | 46 +-- .../legal-document-update.component.spec.ts | 15 +- .../competency-form.component.spec.ts | 8 +- .../edit-competency.component.spec.ts | 8 +- .../edit-prerequisite.component.spec.ts | 8 +- ...cy-recommendation-detail.component.spec.ts | 4 +- .../prerequisite-form.component.spec.ts | 9 +- .../course/course-update.component.spec.ts | 2 +- ...g-and-drop-question-edit.component.spec.ts | 33 +- .../exam/exam-update.component.spec.ts | 6 +- ...nnouncement-create-modal.component.spec.ts | 9 +- .../exercise-hint-update.component.spec.ts | 4 +- ...multiple-choice-question.component.spec.ts | 4 +- .../text-unit-form.component.spec.ts | 2 +- .../lecture/lecture-update.component.spec.ts | 4 +- .../lecture-wizard-title.component.spec.ts | 4 +- .../markdown-editor-monaco.component.spec.ts | 30 +- .../markdown-editor-parsing.helper.spec.ts | 51 ++++ ...ple-choice-question-edit.component.spec.ts | 44 +-- ...ing-instructions-details.component.spec.ts | 100 +++--- ...aco-editor-action-quiz.integration.spec.ts | 40 +++ .../monaco-editor-action.integration.spec.ts | 2 +- ...r-grading-instructions.integration.spec.ts | 74 +++++ .../monaco-editor.component.spec.ts | 6 + .../knowledge-area-edit.component.spec.ts | 4 +- .../standardized-competency-edit.spec.ts | 4 +- .../tutorial-group-form.component.spec.ts | 2 +- ...code-editor-instructor.integration.spec.ts | 2 - .../course/CourseCommunicationPage.ts | 4 +- .../pageobjects/exam/ExamCreationPage.ts | 7 +- .../pageobjects/exam/ExamManagementPage.ts | 2 +- .../FileUploadExerciseCreationPage.ts | 2 +- .../quiz/QuizExerciseCreationPage.ts | 8 +- .../text/TextExerciseCreationPage.ts | 2 +- .../lecture/LectureCreationPage.ts | 2 +- .../lecture/LectureManagementPage.ts | 2 +- 103 files changed, 1264 insertions(+), 629 deletions(-) delete mode 100644 src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.scss create mode 100644 src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-parsing.helper.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action.ts create mode 100644 src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action.ts create mode 100644 src/test/javascript/spec/component/markdown-editor/markdown-editor-parsing.helper.spec.ts create mode 100644 src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-grading-instructions.integration.spec.ts diff --git a/src/main/webapp/app/admin/legal/legal-document-update.component.html b/src/main/webapp/app/admin/legal/legal-document-update.component.html index d581d9dcf664..7ab8f31edb25 100644 --- a/src/main/webapp/app/admin/legal/legal-document-update.component.html +++ b/src/main/webapp/app/admin/legal/legal-document-update.component.html @@ -3,15 +3,14 @@

-
@if (!unsavedChanges && !isSaving) { @@ -34,13 +33,7 @@

}

- diff --git a/src/main/webapp/app/admin/legal/legal-document-update.component.ts b/src/main/webapp/app/admin/legal/legal-document-update.component.ts index 11151a4410c1..cbe5aafc7cd5 100644 --- a/src/main/webapp/app/admin/legal/legal-document-update.component.ts +++ b/src/main/webapp/app/admin/legal/legal-document-update.component.ts @@ -1,14 +1,14 @@ import { AfterContentChecked, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { faBan, faCheckCircle, faCircleNotch, faExclamationTriangle, faSave } from '@fortawesome/free-solid-svg-icons'; import { LegalDocumentService } from 'app/shared/service/legal-document.service'; -import { MarkdownEditorComponent, MarkdownEditorHeight } from 'app/shared/markdown-editor/markdown-editor.component'; +import { MarkdownEditorHeight } from 'app/shared/markdown-editor/markdown-editor.component'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { UnsavedChangesWarningComponent } from 'app/admin/legal/unsaved-changes-warning/unsaved-changes-warning.component'; import { LegalDocument, LegalDocumentLanguage, LegalDocumentType } from 'app/entities/legal-document.model'; import { ActivatedRoute } from '@angular/router'; import { Observable, tap } from 'rxjs'; import { JhiLanguageHelper } from 'app/core/language/language.helper'; -import { ArtemisMarkdownService } from 'app/shared/markdown.service'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; @Component({ selector: 'jhi-privacy-statement-update-component', @@ -35,12 +35,12 @@ export class LegalDocumentUpdateComponent implements OnInit, AfterContentChecked legalDocumentType: LegalDocumentType = LegalDocumentType.PRIVACY_STATEMENT; unsavedChanges = false; isSaving = false; - @ViewChild(MarkdownEditorComponent, { static: false }) markdownEditor: MarkdownEditorComponent; + @ViewChild(MarkdownEditorMonacoComponent, { static: false }) markdownEditor: MarkdownEditorMonacoComponent; + currentContentTrimmed = ''; currentLanguage = this.DEFAULT_LANGUAGE; unsavedChangesWarning: NgbModalRef; titleKey: string; - private languageChangeInPreview: boolean; constructor( private legalDocumentService: LegalDocumentService, @@ -48,7 +48,6 @@ export class LegalDocumentUpdateComponent implements OnInit, AfterContentChecked private route: ActivatedRoute, private languageHelper: JhiLanguageHelper, private changeDetectorRef: ChangeDetectorRef, - private markdownService: ArtemisMarkdownService, ) {} ngOnInit() { @@ -84,7 +83,7 @@ export class LegalDocumentUpdateComponent implements OnInit, AfterContentChecked updateLegalDocument() { this.isSaving = true; - this.legalDocument.text = this.markdownEditor.markdown!; + this.legalDocument.text = this.currentContentTrimmed; if (this.legalDocumentType === LegalDocumentType.PRIVACY_STATEMENT) { this.legalDocumentService.updatePrivacyStatement(this.legalDocument).subscribe((statement) => { this.setUpdatedDocument(statement); @@ -102,29 +101,27 @@ export class LegalDocumentUpdateComponent implements OnInit, AfterContentChecked this.isSaving = false; } - checkUnsavedChanges(content: string) { + onContentChanged(content: string) { + this.currentContentTrimmed = content.trim(); this.unsavedChanges = content !== this.legalDocument.text; } - onLanguageChange(legalDocumentLanguage: any) { + onLanguageChange(legalDocumentLanguage: LegalDocumentLanguage) { if (this.unsavedChanges) { this.showWarning(legalDocumentLanguage); } else { - this.markdownEditor.markdown = ''; this.currentLanguage = legalDocumentLanguage; this.getLegalDocumentForUpdate(this.legalDocumentType, legalDocumentLanguage).subscribe((document) => { this.legalDocument = document; + this.markdownEditor.markdown = this.legalDocument.text; + // Ensure the new text is parsed and displayed in the preview + this.markdownEditor.parseMarkdown(); this.unsavedChanges = false; - // if we are currently in preview mode, we need to update the preview - if (this.markdownEditor.previewMode) { - this.markdownEditor.previewTextAsHtml = this.markdownService.safeHtmlForMarkdown(this.legalDocument.text); - this.languageChangeInPreview = true; - } }); } } - showWarning(legalDocumentLanguage: any) { + showWarning(legalDocumentLanguage: LegalDocumentLanguage) { this.unsavedChangesWarning = this.modalService.open(UnsavedChangesWarningComponent, { size: 'lg', backdrop: 'static' }); if (this.legalDocumentType === LegalDocumentType.PRIVACY_STATEMENT) { this.unsavedChangesWarning.componentInstance.textMessage = 'artemisApp.legal.privacyStatement.unsavedChangesWarning'; @@ -151,16 +148,4 @@ export class LegalDocumentUpdateComponent implements OnInit, AfterContentChecked ngAfterContentChecked() { this.changeDetectorRef.detectChanges(); } - - /** - * If the language is changed while we are in the preview mode, we must trigger a change event, so the ace editor updates its content. - * We must do this when the editor is visible because otherwise the editor will only be updated if you click on it once. - */ - updateTextIfLanguageChangedInPreview() { - if (this.languageChangeInPreview) { - // we have to trigger a change event, so the ace editor updates its content - this.markdownEditor.aceEditorContainer.getEditor().session._emit('change', { start: { row: 0, column: 0 }, end: { row: 0, column: 0 }, action: 'insert', lines: [] }); - this.languageChangeInPreview = false; - } - } } diff --git a/src/main/webapp/app/admin/standardized-competencies/knowledge-area-edit.component.html b/src/main/webapp/app/admin/standardized-competencies/knowledge-area-edit.component.html index 5121a3a30893..249e72addc6b 100644 --- a/src/main/webapp/app/admin/standardized-competencies/knowledge-area-edit.component.html +++ b/src/main/webapp/app/admin/standardized-competencies/knowledge-area-edit.component.html @@ -62,7 +62,7 @@

@if (isEditing) { -

@if (isEditing) { - onError(this.alertService, errorResponse), }); @@ -130,6 +133,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe this.isEditing = false; this.selectedKnowledgeArea = undefined; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => this.dialogErrorSource.next(error.message), }); @@ -152,6 +156,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe if (!(this.selectedKnowledgeArea?.id || this.selectedCompetency) && !this.isEditing) { this.selectedKnowledgeArea = resultKnowledgeArea; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => onError(this.alertService, error), }); @@ -167,6 +172,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe if (resultKnowledgeArea.id === this.selectedKnowledgeArea?.id) { this.selectedKnowledgeArea = resultKnowledgeArea; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => onError(this.alertService, error), }); @@ -205,6 +211,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe this.isEditing = false; this.selectedCompetency = undefined; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => this.dialogErrorSource.next(error.message), }); @@ -227,6 +234,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe if (!(this.selectedCompetency?.id || this.selectedKnowledgeArea) && !this.isEditing) { this.selectedCompetency = resultCompetency; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => onError(this.alertService, error), }); @@ -244,6 +252,7 @@ export class StandardizedCompetencyManagementComponent extends StandardizedCompe if (resultCompetency.id === this.selectedCompetency?.id) { this.selectedCompetency = resultCompetency; } + this.changeDetectorRef.detectChanges(); }, error: (error: HttpErrorResponse) => onError(this.alertService, error), }); diff --git a/src/main/webapp/app/course/competencies/competency.module.ts b/src/main/webapp/app/course/competencies/competency.module.ts index 815be526a131..d7b4c6da30b5 100644 --- a/src/main/webapp/app/course/competencies/competency.module.ts +++ b/src/main/webapp/app/course/competencies/competency.module.ts @@ -23,6 +23,7 @@ import { JudgementOfLearningRatingComponent } from 'app/course/competencies/judg import { CompetencyManagementTableComponent } from 'app/course/competencies/competency-management/competency-management-table.component'; import { CompetencySearchComponent } from 'app/course/competencies/import/competency-search.component'; import { ImportCompetenciesTableComponent } from 'app/course/competencies/import/import-competencies-table.component'; +import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; @NgModule({ imports: [ @@ -41,6 +42,7 @@ import { ImportCompetenciesTableComponent } from 'app/course/competencies/import RatingModule, JudgementOfLearningRatingComponent, CompetencyManagementTableComponent, + ArtemisMarkdownEditorModule, ], declarations: [ CompetencyRingsComponent, diff --git a/src/main/webapp/app/course/competencies/forms/common-course-competency-form.component.html b/src/main/webapp/app/course/competencies/forms/common-course-competency-form.component.html index 38a8936b2701..c27066b26924 100644 --- a/src/main/webapp/app/course/competencies/forms/common-course-competency-form.component.html +++ b/src/main/webapp/app/course/competencies/forms/common-course-competency-form.component.html @@ -27,7 +27,7 @@ @if (!isInConnectMode) {
- {{ titleControl.value
@if (isInEditMode) { -
- - GitHub Markdown Guide - +

diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-modal.component.html b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-modal.component.html index 0b05bacb6172..d6ec36ee35e0 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-modal.component.html +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-modal.component.html @@ -9,15 +9,14 @@
- +
- +
- +
- +
@if (!isExamMode) { diff --git a/src/main/webapp/app/exercises/file-upload/manage/file-upload-exercise-update.component.ts b/src/main/webapp/app/exercises/file-upload/manage/file-upload-exercise-update.component.ts index 38e688e7c415..abd489160baa 100644 --- a/src/main/webapp/app/exercises/file-upload/manage/file-upload-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/file-upload/manage/file-upload-exercise-update.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { AlertService, AlertType } from 'app/core/util/alert.service'; @@ -8,7 +8,6 @@ import { CourseManagementService } from 'app/course/manage/course-management.ser import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { Exercise, ExerciseMode, IncludedInOverallScore, getCourseId, resetForImport } from 'app/entities/exercise.model'; import { EditorMode } from 'app/shared/markdown-editor/markdown-editor.component'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { cloneDeep } from 'lodash-es'; @@ -27,10 +26,12 @@ import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-f import { NgModel } from '@angular/forms'; import { Subscription } from 'rxjs'; import { FormSectionStatus } from 'app/forms/form-status-bar/form-status-bar.component'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; @Component({ selector: 'jhi-file-upload-exercise-update', templateUrl: './file-upload-exercise-update.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class FileUploadExerciseUpdateComponent implements AfterViewInit, OnDestroy, OnInit { readonly IncludedInOverallScore = IncludedInOverallScore; @@ -55,8 +56,8 @@ export class FileUploadExerciseUpdateComponent implements AfterViewInit, OnDestr existingCategories: ExerciseCategory[]; EditorMode = EditorMode; notificationText?: string; - domainCommandsProblemStatement = [new KatexCommand()]; - domainCommandsSampleSolution = [new KatexCommand()]; + domainActionsProblemStatement = [new MonacoFormulaAction()]; + domainActionsExampleSolution = [new MonacoFormulaAction()]; isImport: boolean; examCourseId?: number; diff --git a/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.html b/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.html index 05e678ad84d4..23889e51c013 100644 --- a/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.html +++ b/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.html @@ -33,12 +33,11 @@

-
@if (!isExamMode) { @@ -66,12 +65,11 @@

-

} diff --git a/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.ts b/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.ts index 7e66dac4b5d8..1da174b17a01 100644 --- a/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/modeling/manage/modeling-exercise-update.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { HttpErrorResponse } from '@angular/common/http'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; @@ -7,7 +7,6 @@ import { CourseManagementService } from 'app/course/manage/course-management.ser import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { ExerciseMode, IncludedInOverallScore, resetForImport } from 'app/entities/exercise.model'; import { EditorMode } from 'app/shared/markdown-editor/markdown-editor.component'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { switchMap, tap } from 'rxjs/operators'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; @@ -32,10 +31,12 @@ import { NgModel } from '@angular/forms'; import { ExerciseUpdatePlagiarismComponent } from 'app/exercises/shared/plagiarism/exercise-update-plagiarism/exercise-update-plagiarism.component'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; @Component({ selector: 'jhi-modeling-exercise-update', templateUrl: './modeling-exercise-update.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ModelingExerciseUpdateComponent implements AfterViewInit, OnDestroy, OnInit { @ViewChild(ExerciseTitleChannelNameComponent) exerciseTitleChannelNameComponent: ExerciseTitleChannelNameComponent; @@ -65,8 +66,8 @@ export class ModelingExerciseUpdateComponent implements AfterViewInit, OnDestroy exerciseCategories: ExerciseCategory[]; existingCategories: ExerciseCategory[]; notificationText?: string; - domainCommandsProblemStatement = [new KatexCommand()]; - domainCommandsSampleSolution = [new KatexCommand()]; + domainActionsProblemStatement = [new MonacoFormulaAction()]; + domainActionsExampleSolution = [new MonacoFormulaAction()]; examCourseId?: number; isImport: boolean; isExamMode: boolean; diff --git a/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.html b/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.html index 4b697c678b61..677106c40346 100644 --- a/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.html +++ b/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.html @@ -5,8 +5,10 @@ class="overflow-hidden flex-grow-1" [domainActions]="domainActions" [initialEditorHeight]="initialEditorHeight" + [useDefaultMarkdownEditorOptions]="false" [enableResize]="enableResize" [markdown]="exercise.problemStatement" + [showDefaultPreview]="false" (onPreviewSelect)="generateHtml()" (markdownChange)="updateProblemStatement($event)" > diff --git a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.html b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.html index 183061aefb94..4f9c51cf8ead 100644 --- a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.html +++ b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.html @@ -200,29 +200,28 @@

@if (!reEvaluationInProgress) {
-
- } - @if (reEvaluationInProgress) { + } @else {
- diff --git a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts index fde9f929e280..784a16bcffcb 100644 --- a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts @@ -16,14 +16,10 @@ import { DragAndDropQuestionUtil } from 'app/exercises/quiz/shared/drag-and-drop import { DragAndDropMouseEvent } from 'app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-mouse-event.class'; import { DragState } from 'app/entities/quiz/drag-state.enum'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { HintCommand } from 'app/shared/markdown-editor/domainCommands/hint.command'; -import { ExplanationCommand } from 'app/shared/markdown-editor/domainCommands/explanation.command'; import { DragAndDropMapping } from 'app/entities/quiz/drag-and-drop-mapping.model'; import { DragAndDropQuestion } from 'app/entities/quiz/drag-and-drop-question.model'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { DragItem } from 'app/entities/quiz/drag-item.model'; import { DropLocation } from 'app/entities/quiz/drop-location.model'; -import { DomainCommand } from 'app/shared/markdown-editor/domainCommands/domainCommand'; import { QuizQuestionEdit } from 'app/exercises/quiz/manage/quiz-question-edit.interface'; import { cloneDeep } from 'lodash-es'; import { round } from 'app/shared/util/utils'; @@ -52,6 +48,9 @@ import { faFileImage } from '@fortawesome/free-regular-svg-icons'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { MAX_QUIZ_QUESTION_POINTS } from 'app/shared/constants/input.constants'; import { FileService } from 'app/shared/http/file.service'; +import { MonacoQuizHintAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action'; +import { MonacoQuizExplanationAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action'; +import { MarkdownEditorMonacoComponent, TextWithDomainAction } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; @Component({ selector: 'jhi-drag-and-drop-question-edit', @@ -63,7 +62,7 @@ import { FileService } from 'app/shared/http/file.service'; export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, AfterViewInit, QuizQuestionEdit { @ViewChild('clickLayer', { static: false }) private clickLayer: ElementRef; @ViewChild('backgroundImage ', { static: false }) private backgroundImage: SecuredImageComponent; - @ViewChild('markdownEditor', { static: false }) private markdownEditor: MarkdownEditorComponent; + @ViewChild('markdownEditor', { static: false }) private markdownEditor: MarkdownEditorMonacoComponent; @Input() question: DragAndDropQuestion; @Input() questionIndex: number; @@ -107,11 +106,10 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte */ mouse: DragAndDropMouseEvent; - hintCommand = new HintCommand(); - explanationCommand = new ExplanationCommand(); + hintAction = new MonacoQuizHintAction(); + explanationAction = new MonacoQuizExplanationAction(); - /** {array} with domainCommands that are needed for a drag and drop question **/ - dragAndDropQuestionDomainCommands: DomainCommand[] = [this.explanationCommand, this.hintCommand]; + dragAndDropDomainActions = [this.explanationAction, this.hintAction]; // Icons faBan = faBan; @@ -838,20 +836,18 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte } /** - * 1. Gets the {array} containing the text with the domainCommandIdentifier and creates a new drag and drop problem statement - * by assigning the text according to the domainCommandIdentifiers to the drag and drop attributes. - * (question text, explanation, hint) - * @param domainCommands - containing markdownText with the corresponding domainCommand {DomainCommand} identifier + * Creates the drag and drop problem statement from the parsed markdown text, assigning the question text, explanation, and hint according to the domain actions found. + * @param textWithDomainActions The parsed markdown text with the corresponding domain actions. */ - domainCommandsFound(domainCommands: [string, DomainCommand | null][]): void { + domainActionsFound(textWithDomainActions: TextWithDomainAction[]): void { this.cleanupQuestion(); - for (const [text, command] of domainCommands) { - if (command === null && text.length > 0) { + for (const { text, action } of textWithDomainActions) { + if (action === undefined && text.length > 0) { this.question.text = text; } - if (command instanceof ExplanationCommand) { + if (action instanceof MonacoQuizExplanationAction) { this.question.explanation = text; - } else if (command instanceof HintCommand) { + } else if (action instanceof MonacoQuizHintAction) { this.question.hint = text; } } @@ -873,6 +869,6 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte */ prepareForSave(): void { this.cleanupQuestion(); - this.markdownEditor.parse(); + this.markdownEditor.parseMarkdown(); } } diff --git a/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.html b/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.html index de7ab74f204c..9e13e98db8c7 100644 --- a/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.html +++ b/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.html @@ -94,19 +94,20 @@

MC

- - + @if (showMultipleChoiceQuestionPreview) { } @@ -114,13 +115,13 @@

MC

- + @if (showMultipleChoiceQuestionVisual) { - + } -
+
diff --git a/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.ts b/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.ts index 48fdeb5a2c09..014af02dd3b4 100644 --- a/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component.ts @@ -1,29 +1,33 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { HintCommand } from 'app/shared/markdown-editor/domainCommands/hint.command'; -import { ExplanationCommand } from 'app/shared/markdown-editor/domainCommands/explanation.command'; -import { IncorrectOptionCommand } from 'app/shared/markdown-editor/domainCommands/incorrectOptionCommand'; import { AnswerOption } from 'app/entities/quiz/answer-option.model'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { MultipleChoiceQuestion } from 'app/entities/quiz/multiple-choice-question.model'; -import { CorrectOptionCommand } from 'app/shared/markdown-editor/domainCommands/correctOptionCommand'; -import { DomainCommand } from 'app/shared/markdown-editor/domainCommands/domainCommand'; import { QuizQuestionEdit } from 'app/exercises/quiz/manage/quiz-question-edit.interface'; import { generateExerciseHintExplanation } from 'app/shared/util/markdown.util'; import { faAngleDown, faAngleRight, faQuestionCircle, faTrash } from '@fortawesome/free-solid-svg-icons'; import { ScoringType } from 'app/entities/quiz/quiz-question.model'; import { MAX_QUIZ_QUESTION_POINTS } from 'app/shared/constants/input.constants'; +import { MonacoQuizHintAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action'; +import { MonacoWrongMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action'; +import { MonacoCorrectMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action'; +import { MonacoQuizExplanationAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action'; +import { MarkdownEditorMonacoComponent, TextWithDomainAction } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { MultipleChoiceVisualQuestionComponent } from 'app/exercises/quiz/shared/questions/multiple-choice-question/multiple-choice-visual-question.component'; @Component({ selector: 'jhi-multiple-choice-question-edit', templateUrl: './multiple-choice-question-edit.component.html', styleUrls: ['../quiz-exercise.scss', '../../shared/quiz.scss'], encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, }) export class MultipleChoiceQuestionEditComponent implements OnInit, QuizQuestionEdit { @ViewChild('markdownEditor', { static: false }) - private markdownEditor: MarkdownEditorComponent; + private markdownEditor: MarkdownEditorMonacoComponent; + + @ViewChild('visual', { static: false }) + visualChild: MultipleChoiceVisualQuestionComponent; @Input() question: MultipleChoiceQuestion; @@ -43,18 +47,17 @@ export class MultipleChoiceQuestionEditComponent implements OnInit, QuizQuestion /** Set default preview of the markdown editor as preview for the multiple choice question **/ get showPreview(): boolean { - return this.markdownEditor && this.markdownEditor.previewMode; + return this.markdownEditor && this.markdownEditor.inPreviewMode; } showMultipleChoiceQuestionPreview = true; showMultipleChoiceQuestionVisual = true; - hintCommand = new HintCommand(); - correctCommand = new CorrectOptionCommand(); - incorrectCommand = new IncorrectOptionCommand(); - explanationCommand = new ExplanationCommand(); + correctAction = new MonacoCorrectMultipleChoiceAnswerAction(); + wrongAction = new MonacoWrongMultipleChoiceAnswerAction(); + explanationAction = new MonacoQuizExplanationAction(); + hintAction = new MonacoQuizHintAction(); - /** DomainCommands for the multiple choice question **/ - commandMultipleChoiceQuestions: DomainCommand[] = [this.correctCommand, this.incorrectCommand, this.explanationCommand, this.hintCommand]; + multipleChoiceActions = [this.correctAction, this.wrongAction, this.explanationAction, this.hintAction]; // Icons faTrash = faTrash; @@ -131,12 +134,13 @@ export class MultipleChoiceQuestionEditComponent implements OnInit, QuizQuestion * to get the newest values in the editor to update the question attributes */ prepareForSave(): void { - if (this.markdownEditor.visualMode) { - this.markdownEditor.markdown = this.markdownEditor.visualChild.parseQuestion(); - } - this.cleanupQuestion(); - this.markdownEditor.parse(); + this.markdownEditor.parseMarkdown(); + } + + onLeaveVisualTab(): void { + this.markdownEditor.markdown = this.visualChild.parseQuestion(); + this.prepareForSave(); } /** @@ -153,34 +157,34 @@ export class MultipleChoiceQuestionEditComponent implements OnInit, QuizQuestion } /** - * 1. Gets a tuple of text and domainCommandIdentifiers and assigns text values according to the domainCommandIdentifiers a + * 1. Gets a tuple of text and domain action identifiers and assigns text values according to the domain actions a * multiple choice question the to the multiple choice question attributes. * (question text, explanation, hint, answerOption (correct/wrong) - * 2. The tuple order is the same as the order of the commands in the markdown text inserted by the user + * 2. The tuple order is the same as the order of the actions in the markdown text inserted by the user * 3. resetMultipleChoicePreview() is triggered to notify the parent component * about the changes within the question and to cacheValidation() since the assigned values have changed - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - domainCommandsFound(domainCommands: [string, DomainCommand | null][]): void { + domainActionsFound(textWithDomainActions: TextWithDomainAction[]): void { this.cleanupQuestion(); let currentAnswerOption; - for (const [text, command] of domainCommands) { - if (command === null && text.length > 0) { + for (const { text, action } of textWithDomainActions) { + if (action === undefined && text.length > 0) { this.question.text = text; } - if (command instanceof CorrectOptionCommand || command instanceof IncorrectOptionCommand) { + if (action instanceof MonacoCorrectMultipleChoiceAnswerAction || action instanceof MonacoWrongMultipleChoiceAnswerAction) { currentAnswerOption = new AnswerOption(); - currentAnswerOption.isCorrect = command instanceof CorrectOptionCommand; + currentAnswerOption.isCorrect = action instanceof MonacoCorrectMultipleChoiceAnswerAction; currentAnswerOption.text = text; this.question.answerOptions!.push(currentAnswerOption); - } else if (command instanceof ExplanationCommand) { + } else if (action instanceof MonacoQuizExplanationAction) { if (currentAnswerOption) { currentAnswerOption.explanation = text; } else { this.question.explanation = text; } - } else if (command instanceof HintCommand) { + } else if (action instanceof MonacoQuizHintAction) { if (currentAnswerOption) { currentAnswerOption.hint = text; } else { diff --git a/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.html b/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.html index 29f375533509..b6b99fc4ebac 100644 --- a/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.html +++ b/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.html @@ -1,3 +1,4 @@ +
@@ -135,17 +136,17 @@

MC

- MC

- diff --git a/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.ts b/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.ts index 39489c556064..acf8aea5f8d2 100644 --- a/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component.ts @@ -26,6 +26,7 @@ export class ReEvaluateMultipleChoiceQuestionComponent implements OnInit { editorMode = EditorMode.NONE; markdownMap: Map; + questionText: string; // Create Backup Question for resets @Input() backupQuestion: MultipleChoiceQuestion; @@ -49,6 +50,7 @@ export class ReEvaluateMultipleChoiceQuestionComponent implements OnInit { (answer.isCorrect ? CorrectOptionCommand.IDENTIFIER : IncorrectOptionCommand.IDENTIFIER) + ' ' + generateExerciseHintExplanation(answer), ); } + this.questionText = this.getQuestionText(this.question); } /** diff --git a/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.html b/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.html index 8372aea83c43..49822af7d4d7 100644 --- a/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.html +++ b/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.html @@ -287,6 +287,7 @@

diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.html b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.html index 1235391ec365..5c80f6e0c868 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.html +++ b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.html @@ -60,15 +60,8 @@

- +
+
@if (exerciseHint.type === HintType.CODE) {
diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts index 3ea7292de040..c4c7b78f0496 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts @@ -4,8 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { Observable, Subscription, filter, switchMap } from 'rxjs'; import { AlertService } from 'app/core/util/alert.service'; import { ExerciseHintService } from '../shared/exercise-hint.service'; -import { EditorMode, MarkdownEditorHeight } from 'app/shared/markdown-editor/markdown-editor.component'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; +import { MarkdownEditorHeight } from 'app/shared/markdown-editor/markdown-editor.component'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; import { faBan, faCircleNotch, faSave } from '@fortawesome/free-solid-svg-icons'; import { ExerciseHint, HintType } from 'app/entities/hestia/exercise-hint.model'; @@ -23,13 +22,13 @@ import { IrisSettings } from 'app/entities/iris/settings/iris-settings.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ButtonType } from 'app/shared/components/button.component'; import { PROFILE_IRIS } from 'app/app.constants'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; const DEFAULT_DISPLAY_THRESHOLD = 3; @Component({ selector: 'jhi-exercise-hint-update', templateUrl: './exercise-hint-update.component.html', - styleUrls: ['./exercise-hint.scss'], }) export class ExerciseHintUpdateComponent implements OnInit, OnDestroy { MarkdownEditorHeight = MarkdownEditorHeight; @@ -47,8 +46,7 @@ export class ExerciseHintUpdateComponent implements OnInit, OnDestroy { isGeneratingDescription: boolean; paramSub: Subscription; - domainCommands = [new KatexCommand()]; - editorMode = EditorMode.LATEX; + domainActions = [new MonacoFormulaAction()]; // Icons faCircleNotch = faCircleNotch; diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.scss b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.scss deleted file mode 100644 index 536b30c1def3..000000000000 --- a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.scss +++ /dev/null @@ -1,5 +0,0 @@ -.hint-form__editor-wrapper { - ::ng-deep .markdown-editor { - height: 300px; - } -} diff --git a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.html b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.html index be9cf1f0e6cd..fccbe00c9353 100644 --- a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.html +++ b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.html @@ -151,15 +151,17 @@ @if (!showEditMode) {
-
} @@ -172,13 +174,13 @@
-
-
+
@if (criteria.structuredGradingInstructions!) {
- @for (instruction of criteria.structuredGradingInstructions; track instruction) { + @for (instruction of criteria.structuredGradingInstructions; track instruction; let index = $index) {
-
- +
diff --git a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.scss b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.scss index 6ec55ecf1d9e..74e64144c104 100644 --- a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.scss +++ b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.scss @@ -37,10 +37,6 @@ width: auto; } - .input-group > input { - height: 100%; - } - .form-group { display: flex; align-items: center; diff --git a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.ts b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.ts index 0215dcbfe5d5..64448a6f4569 100644 --- a/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.ts +++ b/src/main/webapp/app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component.ts @@ -1,18 +1,19 @@ import { AfterContentInit, ChangeDetectorRef, Component, Input, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; -import { UsageCountCommand } from 'app/shared/markdown-editor/domainCommands/usageCount.command'; -import { CreditsCommand } from 'app/shared/markdown-editor/domainCommands/credits.command'; -import { FeedbackCommand } from 'app/shared/markdown-editor/domainCommands/feedback.command'; -import { DomainCommand } from 'app/shared/markdown-editor/domainCommands/domainCommand'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; +import { MarkdownEditorHeight } from 'app/shared/markdown-editor/markdown-editor.component'; import { GradingInstruction } from 'app/exercises/shared/structured-grading-criterion/grading-instruction.model'; -import { GradingScaleCommand } from 'app/shared/markdown-editor/domainCommands/gradingScaleCommand'; -import { GradingInstructionCommand } from 'app/shared/markdown-editor/domainCommands/gradingInstruction.command'; -import { InstructionDescriptionCommand } from 'app/shared/markdown-editor/domainCommands/instructionDescription.command'; -import { GradingCriterionCommand } from 'app/shared/markdown-editor/domainCommands/gradingCriterionCommand'; import { Exercise } from 'app/entities/exercise.model'; import { cloneDeep } from 'lodash-es'; import { faPlus, faTrash, faUndo } from '@fortawesome/free-solid-svg-icons'; +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import { MonacoGradingCreditsAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action'; +import { MonacoGradingScaleAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action'; +import { MonacoGradingDescriptionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action'; +import { MonacoGradingFeedbackAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action'; +import { MonacoGradingUsageCountAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action'; +import { MarkdownEditorMonacoComponent, TextWithDomainAction } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { MonacoGradingCriterionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action'; +import { MonacoGradingInstructionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action'; @Component({ selector: 'jhi-grading-instructions-details', @@ -23,9 +24,9 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent /** Ace Editor configuration constants **/ markdownEditorText = ''; @ViewChildren('markdownEditors') - private markdownEditors: QueryList; + private markdownEditors: QueryList; @ViewChild('markdownEditor', { static: false }) - private markdownEditor: MarkdownEditorComponent; + private markdownEditor: MarkdownEditorMonacoComponent; @Input() exercise: Exercise; private instructions: GradingInstruction[]; @@ -33,32 +34,32 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent backupExercise: Exercise; - gradingCriterionCommand = new GradingCriterionCommand(); - gradingInstructionCommand = new GradingInstructionCommand(); - creditsCommand = new CreditsCommand(); - gradingScaleCommand = new GradingScaleCommand(); - instructionDescriptionCommand = new InstructionDescriptionCommand(); - feedbackCommand = new FeedbackCommand(); - usageCountCommand = new UsageCountCommand(); + creditsAction = new MonacoGradingCreditsAction(); + gradingScaleAction = new MonacoGradingScaleAction(); + descriptionAction = new MonacoGradingDescriptionAction(); + feedbackAction = new MonacoGradingFeedbackAction(); + usageCountAction = new MonacoGradingUsageCountAction(); + gradingInstructionAction = new MonacoGradingInstructionAction(this.creditsAction, this.gradingScaleAction, this.descriptionAction, this.feedbackAction, this.usageCountAction); + gradingCriterionAction = new MonacoGradingCriterionAction(this.gradingInstructionAction); + + domainActionsForMainEditor = [ + this.creditsAction, + this.gradingScaleAction, + this.descriptionAction, + this.feedbackAction, + this.usageCountAction, + this.gradingInstructionAction, + this.gradingCriterionAction, + ]; showEditMode: boolean; - domainCommands: DomainCommand[] = [ - this.creditsCommand, - this.gradingScaleCommand, - this.instructionDescriptionCommand, - this.feedbackCommand, - this.usageCountCommand, - this.gradingCriterionCommand, - this.gradingInstructionCommand, - ]; - - domainCommandsGradingInstructions: DomainCommand[] = [ - this.creditsCommand, - this.gradingScaleCommand, - this.instructionDescriptionCommand, - this.feedbackCommand, - this.usageCountCommand, + domainActionsForGradingInstructionParsing: MonacoEditorDomainAction[] = [ + this.creditsAction, + this.gradingScaleAction, + this.descriptionAction, + this.feedbackAction, + this.usageCountAction, ]; // Icons @@ -66,6 +67,8 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent faTrash = faTrash; faUndo = faUndo; + protected readonly MarkdownEditorHeight = MarkdownEditorHeight; + constructor(private changeDetector: ChangeDetectorRef) {} ngOnInit() { @@ -87,7 +90,7 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent this.changeDetector.detectChanges(); this.criteria!.forEach((criterion) => { criterion.structuredGradingInstructions.forEach((instruction) => { - this.markdownEditors.get(index)!.markdownTextChange(this.generateInstructionText(instruction)); + this.markdownEditors.get(index)!.markdown = this.generateInstructionText(instruction); index += 1; }); }); @@ -99,10 +102,10 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent if (this.exercise.gradingCriteria) { for (const criterion of this.exercise.gradingCriteria) { if (criterion.title == undefined) { - // if it is a dummy criterion, leave out the command identifier + // if it is a dummy criterion, leave out the action identifier markdownText += this.generateInstructionsMarkdown(criterion); } else { - markdownText += GradingCriterionCommand.IDENTIFIER + criterion.title + '\n' + '\t' + this.generateInstructionsMarkdown(criterion); + markdownText += `${MonacoGradingCriterionAction.IDENTIFIER} ${criterion.title}\n\t${this.generateInstructionsMarkdown(criterion)}`; } } } @@ -130,7 +133,7 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent generateInstructionText(instruction: GradingInstruction): string { let markdownText = ''; markdownText = - GradingInstructionCommand.IDENTIFIER + + MonacoGradingInstructionAction.IDENTIFIER + '\n' + '\t' + this.generateCreditsText(instruction) + @@ -152,59 +155,52 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } generateCreditsText(instruction: GradingInstruction): string { + const creditsText = MonacoGradingCreditsAction.TEXT; + const creditsIdentifier = MonacoGradingCreditsAction.IDENTIFIER; if (instruction.credits == undefined) { - instruction.credits = parseFloat(CreditsCommand.TEXT); - return CreditsCommand.IDENTIFIER + ' ' + CreditsCommand.TEXT; + instruction.credits = parseFloat(creditsText) || 0; } - return CreditsCommand.IDENTIFIER + ' ' + instruction.credits; + return `${creditsIdentifier} ${instruction.credits || creditsText}`; } generateGradingScaleText(instruction: GradingInstruction): string { if (instruction.gradingScale == undefined) { - instruction.gradingScale = GradingScaleCommand.TEXT; - return GradingScaleCommand.IDENTIFIER + ' ' + GradingScaleCommand.TEXT; + instruction.gradingScale = MonacoGradingScaleAction.TEXT; } - return GradingScaleCommand.IDENTIFIER + ' ' + instruction.gradingScale; + return `${MonacoGradingScaleAction.IDENTIFIER} ${instruction.gradingScale}`; } generateInstructionDescriptionText(instruction: GradingInstruction): string { if (instruction.instructionDescription == undefined) { - instruction.instructionDescription = InstructionDescriptionCommand.TEXT; - return InstructionDescriptionCommand.IDENTIFIER + ' ' + InstructionDescriptionCommand.TEXT; + instruction.instructionDescription = MonacoGradingDescriptionAction.TEXT; } - return InstructionDescriptionCommand.IDENTIFIER + ' ' + instruction.instructionDescription; + return `${MonacoGradingDescriptionAction.IDENTIFIER} ${instruction.instructionDescription}`; } generateInstructionFeedback(instruction: GradingInstruction): string { if (instruction.feedback == undefined) { - instruction.feedback = FeedbackCommand.TEXT; - return FeedbackCommand.IDENTIFIER + ' ' + FeedbackCommand.TEXT; + instruction.feedback = MonacoGradingFeedbackAction.TEXT; } - return FeedbackCommand.IDENTIFIER + ' ' + instruction.feedback; + return `${MonacoGradingFeedbackAction.IDENTIFIER} ${instruction.feedback}`; } generateUsageCount(instruction: GradingInstruction): string { if (instruction.usageCount == undefined) { - instruction.usageCount = parseInt(UsageCountCommand.TEXT, 10); - return UsageCountCommand.IDENTIFIER + ' ' + UsageCountCommand.TEXT; + instruction.usageCount = parseInt(MonacoGradingUsageCountAction.TEXT, 10) || 0; } - return UsageCountCommand.IDENTIFIER + ' ' + instruction.usageCount; + return `${MonacoGradingUsageCountAction.IDENTIFIER} ${instruction.usageCount}`; } initializeExerciseGradingInstructionText(): string { - if (this.exercise.gradingInstructions) { - return this.exercise.gradingInstructions + '\n\n'; - } else { - return 'Add Assessment Instruction text here' + '\n\n'; - } + return `${this.exercise.gradingInstructions || 'Add Assessment Instruction text here'}\n\n`; } prepareForSave(): void { this.cleanupExerciseGradingInstructions(); - this.markdownEditor.parse(); + this.markdownEditor.parseMarkdown(); if (this.exercise.gradingInstructionFeedbackUsed) { this.markdownEditors.forEach((component) => { - component.parse(); + component.parseMarkdown(this.domainActionsForGradingInstructionParsing); }); } } @@ -217,37 +213,33 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent this.exercise.gradingInstructions = undefined; } - hasCriterionCommand(domainCommands: [string, DomainCommand | null][]): boolean { - return domainCommands.some(([, command]) => command instanceof GradingCriterionCommand); + hasCriterionAction(textWithDomainActions: TextWithDomainAction[]): boolean { + return textWithDomainActions.some(({ action }) => action instanceof MonacoGradingCriterionAction); } /** - * @function createSubInstructionCommands - * @desc 1. divides the input: domainCommands in two subarrays: - * instructionCommands, which consists of all stand-alone instructions - * criteriaCommands, which consists of instructions that belong to a criterion - * 2. for each subarrray a method is called to create the criterion and instruction objects - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Creates criterion and instruction objects based on the parsed markdown text. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - createSubInstructionCommands(domainCommands: [string, DomainCommand | null][]): void { - let instructionCommands; - let criteriaCommands; - let endOfInstructionsCommand = 0; - if (!this.hasCriterionCommand(domainCommands)) { - this.setParentForInstructionsWithNoCriterion(domainCommands); + createSubInstructionActions(textWithDomainActions: TextWithDomainAction[]): void { + let instructionActions; + let criterionActions; + let endOfInstructionsAction = 0; + if (!this.hasCriterionAction(textWithDomainActions)) { + this.setParentForInstructionsWithNoCriterion(textWithDomainActions); } else { - for (const [, command] of domainCommands) { - endOfInstructionsCommand++; - this.setExerciseGradingInstructionText(domainCommands); - if (command instanceof GradingCriterionCommand) { - instructionCommands = domainCommands.slice(0, endOfInstructionsCommand - 1); - if (instructionCommands.length !== 0) { - this.setParentForInstructionsWithNoCriterion(instructionCommands); + for (const { action } of textWithDomainActions) { + endOfInstructionsAction++; + this.setExerciseGradingInstructionText(textWithDomainActions); + if (action instanceof MonacoGradingCriterionAction) { + instructionActions = textWithDomainActions.slice(0, endOfInstructionsAction - 1); + if (instructionActions.length !== 0) { + this.setParentForInstructionsWithNoCriterion(instructionActions); } - criteriaCommands = domainCommands.slice(endOfInstructionsCommand - 1); - if (criteriaCommands.length !== 0) { + criterionActions = textWithDomainActions.slice(endOfInstructionsAction - 1); + if (criterionActions.length !== 0) { this.instructions = []; // resets the instructions array to be filled with the instructions of the criteria - this.groupInstructionsToCriteria(criteriaCommands); // creates criterion object for each criterion and their corresponding instruction objects + this.groupInstructionsToCriteria(criterionActions); } break; } @@ -256,14 +248,13 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } /** - * @function setParentForInstructionsWithNoCriterion - * @desc 1. creates a dummy criterion object for each stand-alone instruction - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Creates a dummy grading criterion object for each instruction that does not belong to a criterion and assigns the instruction to it. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - setParentForInstructionsWithNoCriterion(domainCommands: [string, DomainCommand | null][]): void { - for (const [, command] of domainCommands) { - this.setExerciseGradingInstructionText(domainCommands); - if (command instanceof GradingInstructionCommand) { + setParentForInstructionsWithNoCriterion(textWithDomainActions: TextWithDomainAction[]): void { + for (const { action } of textWithDomainActions) { + this.setExerciseGradingInstructionText(textWithDomainActions); + if (action instanceof MonacoGradingInstructionAction) { const dummyCriterion = new GradingCriterion(); const newInstruction = new GradingInstruction(); dummyCriterion.structuredGradingInstructions = []; @@ -273,68 +264,63 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } } this.exercise.gradingCriteria = this.criteria; - this.setInstructionParameters(domainCommands); + this.setInstructionParameters(textWithDomainActions); } /** - * @function groupInstructionsToCriteria - * @desc 1. creates a criterion for each GradingCriterionCommandIdentifier - * and creates the instruction objects of this criterion then assigns them to their parent criterion - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Creates a grading criterion object for each criterion action found in the parsed markdown text and assigns the corresponding grading instructions to it. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - groupInstructionsToCriteria(domainCommands: [string, DomainCommand | null][]): void { - const initialCriteriaCommands = domainCommands; + groupInstructionsToCriteria(textWithDomainActions: TextWithDomainAction[]): void { + const initialCriterionActions = textWithDomainActions; if (this.exercise.gradingCriteria == undefined) { this.exercise.gradingCriteria = []; } - for (const [text, command] of domainCommands) { - if (command instanceof GradingCriterionCommand) { + for (const { text, action } of textWithDomainActions) { + if (action instanceof MonacoGradingCriterionAction) { const newCriterion = new GradingCriterion(); newCriterion.title = text; this.exercise.gradingCriteria.push(newCriterion); newCriterion.structuredGradingInstructions = []; - const modifiedArray = domainCommands.slice(1); // remove GradingCriterionCommandIdentifier after creating its criterion object + const arrayWithoutCriterion = textWithDomainActions.slice(1); // remove the identifier after creating its criterion object let endOfCriterion = 0; - for (const [, instrCommand] of modifiedArray) { + for (const remainingTextWithDomainAction of arrayWithoutCriterion) { + const instrAction = remainingTextWithDomainAction.action; endOfCriterion++; - if (instrCommand instanceof GradingInstructionCommand) { + if (instrAction instanceof MonacoGradingInstructionAction) { const newInstruction = new GradingInstruction(); // create instruction objects that belong to the above created criterion newCriterion.structuredGradingInstructions.push(newInstruction); this.instructions.push(newInstruction); } - if (instrCommand instanceof GradingCriterionCommand) { - domainCommands = domainCommands.slice(endOfCriterion, domainCommands.length); + if (instrAction instanceof MonacoGradingCriterionAction) { + textWithDomainActions = textWithDomainActions.slice(endOfCriterion, textWithDomainActions.length); break; } } } } - this.setInstructionParameters(initialCriteriaCommands.filter(([, command]) => !(command instanceof GradingCriterionCommand))); + this.setInstructionParameters(initialCriterionActions.filter(({ action }) => !(action instanceof MonacoGradingCriterionAction))); } /** - * @function setInstructionParameters - * @desc 1. Gets a tuple of text and domainCommandIdentifiers not including GradingCriterionCommandIdentifiers and assigns text values according to the domainCommandIdentifiers - * 2. The tuple order is the same as the order of the commands in the markdown text inserted by the user - * instruction objects must be created before the method gets triggered - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Sets the parameters of the GradingInstruction objects based on the parsed markdown text. Note that the instruction objects must be created before this method is called. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - - setInstructionParameters(domainCommands: [string, DomainCommand | null][]): void { + setInstructionParameters(textWithDomainActions: TextWithDomainAction[]): void { let index = 0; - for (const [text, command] of domainCommands) { + for (const { text, action } of textWithDomainActions) { if (!this.instructions[index]) { break; } - if (command instanceof CreditsCommand) { + if (action instanceof MonacoGradingCreditsAction) { this.instructions[index].credits = parseFloat(text); - } else if (command instanceof GradingScaleCommand) { + } else if (action instanceof MonacoGradingScaleAction) { this.instructions[index].gradingScale = text; - } else if (command instanceof InstructionDescriptionCommand) { + } else if (action instanceof MonacoGradingDescriptionAction) { this.instructions[index].instructionDescription = text; - } else if (command instanceof FeedbackCommand) { + } else if (action instanceof MonacoGradingFeedbackAction) { this.instructions[index].feedback = text; - } else if (command instanceof UsageCountCommand) { + } else if (action instanceof MonacoGradingUsageCountAction) { this.instructions[index].usageCount = parseInt(text, 10); index++; // index must be increased after the last parameter of the instruction to continue with the next instruction object } @@ -342,28 +328,19 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } /** - * @function domainCommandsFound - * @desc 1. Gets a tuple of text and domainCommandIdentifiers and assigns text values according to the domainCommandIdentifiers - * 2. The tuple order is the same as the order of the commands in the markdown text inserted by the user - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Updates the grading instructions of the exercise based on the parsed markdown text. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - domainCommandsFound(domainCommands: [string, DomainCommand | null][]): void { + onDomainActionsFound(textWithDomainActions: TextWithDomainAction[]): void { this.instructions = []; this.criteria = []; this.exercise.gradingCriteria = []; - this.createSubInstructionCommands(domainCommands); + this.createSubInstructionActions(textWithDomainActions); } - /** - * @function onInstructionChange - * @desc 1. Gets a tuple of text and domainCommandIdentifiers and assigns text values according to the domainCommandIdentifiers - * 2. The tuple order is the same as the order of the commands in the markdown text inserted by the user - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] - * @param {GradingInstruction} instruction - */ - onInstructionChange(domainCommands: [string, DomainCommand | null][], instruction: GradingInstruction): void { + onInstructionChange(textWithDomainActions: TextWithDomainAction[], instruction: GradingInstruction): void { this.instructions = [instruction]; - this.setInstructionParameters(domainCommands); + this.setInstructionParameters(textWithDomainActions); } /** @@ -423,9 +400,8 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } /** - * @function addNewInstruction - * @desc Adds new grading instruction for desired grading criteria - * @param criterion {GradingCriterion} the criteria, which includes the instruction that will be inserted + * Adds a new grading instruction for the specified grading criterion. + * @param criterion The grading criterion that contains the instruction to insert. */ addNewInstruction(criterion: GradingCriterion) { const criterionIndex = this.exercise.gradingCriteria!.indexOf(criterion); @@ -438,10 +414,6 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent this.initializeMarkdown(); } - /** - * @function addNewGradingCriteria - * @desc Adds new grading criteria for the exercise - */ addNewGradingCriterion() { const criterion = new GradingCriterion(); criterion.structuredGradingInstructions = []; @@ -453,21 +425,11 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } } - /** - * @function onCriteriaTitleChange - * @desc Detects changes for grading criteria title - * @param {GradingCriterion} criterion the criteria, which includes title that will be changed - */ onCriterionTitleChange($event: any, criterion: GradingCriterion) { const criterionIndex = this.exercise.gradingCriteria!.indexOf(criterion); this.exercise.gradingCriteria![criterionIndex].title = $event.target.value; } - /** - * @function resetCriteriaTitle - * @desc Resets the whole grading criteria title - * @param criterion {GradingCriterion} the criteria, which includes title that will be reset - */ resetCriterionTitle(criterion: GradingCriterion) { const criterionIndex = this.findCriterionIndex(criterion, this.exercise); const backupCriterionIndex = this.findCriterionIndex(criterion, this.backupExercise); @@ -478,24 +440,21 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent } } - /** - * @function deleteGradingCriteria - * @desc Deletes the grading criteria with sub-grading instructions - * @param criterion {GradingCriterion} the criteria, which will be deleted - */ deleteGradingCriterion(criterion: GradingCriterion) { const criterionIndex = this.exercise.gradingCriteria!.indexOf(criterion); this.exercise.gradingCriteria!.splice(criterionIndex, 1); } /** - * @function setExerciseGradingInstructionText - * @desc Gets a tuple of text and domainCommandIdentifiers and assigns text values as grading instructions of exercise - * @param domainCommands containing tuples of [text, domainCommandIdentifiers] + * Extracts the exercise grading instruction text from the start of the parsed markdown text. + * @param textWithDomainActions The parsed text segments with their corresponding domain actions. */ - setExerciseGradingInstructionText(domainCommands: [string, DomainCommand | null][]): void { - const [text, command] = domainCommands[0]; - if (command === null && text.length > 0) { + setExerciseGradingInstructionText(textWithDomainActions: TextWithDomainAction[]): void { + if (!textWithDomainActions.length) { + return; + } + const { text, action } = textWithDomainActions[0]; + if (action === undefined && text.length > 0) { this.exercise.gradingInstructions = text; } } @@ -509,12 +468,6 @@ export class GradingInstructionsDetailsComponent implements OnInit, AfterContent this.markdownEditorText = this.generateMarkdown(); } - /** - * Updates given grading instruction in exercise - * - * @param instruction needs to be updated - * @param criterion includes instruction needs to be updated - */ updateGradingInstruction(instruction: GradingInstruction, criterion: GradingCriterion) { const criterionIndex = this.exercise.gradingCriteria!.indexOf(criterion); const instructionIndex = this.exercise.gradingCriteria![criterionIndex].structuredGradingInstructions.indexOf(instruction); diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.html b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.html index 2e5a417b7c41..5df2017d2538 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.html +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.html @@ -33,12 +33,11 @@

-
@@ -57,12 +56,11 @@

-
diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts index 21011cacb571..e55e5fb28db2 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { HttpErrorResponse } from '@angular/common/http'; import { TextExercise } from 'app/entities/text-exercise.model'; @@ -7,8 +7,6 @@ import { CourseManagementService } from 'app/course/manage/course-management.ser import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { ExerciseMode, IncludedInOverallScore, resetForImport } from 'app/entities/exercise.model'; -import { EditorMode } from 'app/shared/markdown-editor/markdown-editor.component'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; import { switchMap, tap } from 'rxjs/operators'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; import { NgForm, NgModel } from '@angular/forms'; @@ -31,10 +29,12 @@ import { FormSectionStatus } from 'app/forms/form-status-bar/form-status-bar.com import { ExerciseUpdatePlagiarismComponent } from 'app/exercises/shared/plagiarism/exercise-update-plagiarism/exercise-update-plagiarism.component'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; @Component({ selector: 'jhi-text-exercise-update', templateUrl: './text-exercise-update.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TextExerciseUpdateComponent implements OnInit, OnDestroy, AfterViewInit { readonly IncludedInOverallScore = IncludedInOverallScore; @@ -56,7 +56,6 @@ export class TextExerciseUpdateComponent implements OnInit, OnDestroy, AfterView isExamMode: boolean; isImport = false; goBackAfterSaving = false; - EditorMode = EditorMode; AssessmentType = AssessmentType; isAthenaEnabled$: Observable | undefined; @@ -67,8 +66,8 @@ export class TextExerciseUpdateComponent implements OnInit, OnDestroy, AfterView existingCategories: ExerciseCategory[]; notificationText?: string; - domainCommandsProblemStatement = [new KatexCommand()]; - domainCommandsSampleSolution = [new KatexCommand()]; + domainActionsProblemStatement = [new MonacoFormulaAction()]; + domainActionsExampleSolution = [new MonacoFormulaAction()]; formSectionStatus: FormSectionStatus[]; diff --git a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/text-unit-form/text-unit-form.component.html b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/text-unit-form/text-unit-form.component.html index 0bf5784ea593..7af504cfd0aa 100644 --- a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/text-unit-form/text-unit-form.component.html +++ b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/text-unit-form/text-unit-form.component.html @@ -44,7 +44,13 @@ GitHub Markdown Guide - +
diff --git a/src/main/webapp/app/lecture/lecture-update.component.html b/src/main/webapp/app/lecture/lecture-update.component.html index 67f423adda06..25a522f09f4f 100644 --- a/src/main/webapp/app/lecture/lecture-update.component.html +++ b/src/main/webapp/app/lecture/lecture-update.component.html @@ -30,12 +30,7 @@

- +
diff --git a/src/main/webapp/app/lecture/lecture-update.component.ts b/src/main/webapp/app/lecture/lecture-update.component.ts index 592d937228cb..e0ac895d50ce 100644 --- a/src/main/webapp/app/lecture/lecture-update.component.ts +++ b/src/main/webapp/app/lecture/lecture-update.component.ts @@ -6,15 +6,14 @@ import { AlertService } from 'app/core/util/alert.service'; import { LectureService } from './lecture.service'; import { CourseManagementService } from '../course/manage/course-management.service'; import { Lecture } from 'app/entities/lecture.model'; -import { EditorMode } from 'app/shared/markdown-editor/markdown-editor.component'; import { Course } from 'app/entities/course.model'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; import { onError } from 'app/shared/util/global.utils'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; import { DocumentationType } from 'app/shared/components/documentation-button/documentation-button.component'; import { faBan, faHandshakeAngle, faPuzzlePiece, faQuestionCircle, faSave } from '@fortawesome/free-solid-svg-icons'; import { LectureUpdateWizardComponent } from 'app/lecture/wizard-mode/lecture-update-wizard.component'; import { FILE_EXTENSIONS } from 'app/shared/constants/file-extensions.constants'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; @Component({ selector: 'jhi-lecture-update', @@ -26,7 +25,6 @@ export class LectureUpdateComponent implements OnInit { @ViewChild(LectureUpdateWizardComponent, { static: false }) wizardComponent: LectureUpdateWizardComponent; - EditorMode = EditorMode; lecture: Lecture; isSaving: boolean; isProcessing: boolean; @@ -35,7 +33,7 @@ export class LectureUpdateComponent implements OnInit { courses: Course[]; - domainCommandsDescription = [new KatexCommand()]; + domainActionsDescription = [new MonacoFormulaAction()]; file: File; fileName: string; fileInputTouched = false; diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.html b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.html index 9656e52daf04..9100d8436184 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.html +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.html @@ -6,6 +6,6 @@

- +

diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.ts b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.ts index 8748b9232417..c8b89b284ffb 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.ts +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-title.component.ts @@ -1,7 +1,6 @@ import { Component, Input } from '@angular/core'; -import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'; -import { EditorMode } from 'app/shared/markdown-editor/markdown-editor.component'; import { Lecture } from 'app/entities/lecture.model'; +import { MonacoFormulaAction } from 'app/shared/monaco-editor/model/actions/monaco-formula.action'; @Component({ selector: 'jhi-lecture-update-wizard-title', @@ -11,8 +10,7 @@ export class LectureUpdateWizardTitleComponent { @Input() currentStep: number; @Input() lecture: Lecture; - domainCommandsDescription = [new KatexCommand()]; - EditorMode = EditorMode; + domainActionsDescription = [new MonacoFormulaAction()]; constructor() {} } diff --git a/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.scss b/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.scss index 008cc9349fe4..935730fc5c81 100644 --- a/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.scss +++ b/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.scss @@ -108,7 +108,7 @@ } .background-editor-high { - overflow: scroll; + overflow: auto; } .dropdown-menu { diff --git a/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.ts b/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.ts index 1795b4718b6e..77910b630a20 100644 --- a/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.ts +++ b/src/main/webapp/app/shared/markdown-editor/markdown-editor.component.ts @@ -41,7 +41,7 @@ import { InteractiveSearchCommand } from 'app/shared/markdown-editor/commands/in export enum MarkdownEditorHeight { INLINE = 100, - SMALL = 200, + SMALL = 300, MEDIUM = 500, LARGE = 1000, EXTRA_LARGE = 1500, diff --git a/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html b/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html index 075014915cf8..52d80f585633 100644 --- a/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html +++ b/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html @@ -2,17 +2,18 @@
- @if (enableResize && !inPreviewMode) { + @if (enableResize && inEditMode) {
(); + @Output() + onBlurEditor = new EventEmitter(); + + @Output() + textWithDomainActionsFound = new EventEmitter(); + + @Output() + onDefaultPreviewHtmlChanged = new EventEmitter(); + + @Output() + onLeaveVisualTab = new EventEmitter(); + + defaultPreviewHtml: SafeHtml | undefined; inPreviewMode = false; + inVisualMode = false; + inEditMode = true; uniqueMarkdownEditorId: string; resizeObserver?: ResizeObserver; targetWrapperHeight?: number; + minWrapperHeight?: number; constrainDragPositionFn?: (pointerPosition: Point) => Point; isResizing = false; displayedActions: MarkdownActionsByGroup = { @@ -186,19 +222,27 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie colorSignal: Signal = computed(() => [...this.colorToClassMap.keys()]); + static readonly TAB_EDIT = 'editor_edit'; + static readonly TAB_PREVIEW = 'editor_preview'; + static readonly TAB_VISUAL = 'editor_visual'; readonly colorPickerMarginTop = 35; readonly colorPickerHeight = 110; // Icons protected readonly faQuestionCircle = faQuestionCircle; protected readonly faGripLines = faGripLines; protected readonly faAngleDown = faAngleDown; - // Types exposed to the template + // Types and values exposed to the template protected readonly LectureUnitType = LectureUnitType; protected readonly ReferenceType = ReferenceType; + // We cannot reference these static fields in the template, so we expose them here. + protected readonly TAB_EDIT = MarkdownEditorMonacoComponent.TAB_EDIT; + protected readonly TAB_PREVIEW = MarkdownEditorMonacoComponent.TAB_PREVIEW; + protected readonly TAB_VISUAL = MarkdownEditorMonacoComponent.TAB_VISUAL; constructor( private alertService: AlertService, private fileUploaderService: FileUploaderService, + private artemisMarkdown: ArtemisMarkdownService, ) { this.uniqueMarkdownEditorId = 'markdown-editor-' + uuid(); } @@ -206,24 +250,33 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie ngAfterContentInit(): void { // Affects the template - done in this method to avoid ExpressionChangedAfterItHasBeenCheckedErrors. this.targetWrapperHeight = this.initialEditorHeight !== EXTERNAL_HEIGHT ? this.initialEditorHeight.valueOf() : undefined; + this.minWrapperHeight = this.resizableMinHeight.valueOf(); this.constrainDragPositionFn = this.constrainDragPosition.bind(this); this.displayedActions = { - standard: this.defaultActions, - header: this.headerActions?.actions ?? [], - color: this.colorAction, + standard: this.filterDisplayedActions(this.defaultActions), + header: this.filterDisplayedActions(this.headerActions?.actions ?? []), + color: this.filterDisplayedAction(this.colorAction), domain: { - withoutOptions: this.domainActions.filter((action) => !(action instanceof MonacoEditorDomainActionWithOptions)), - withOptions: this.domainActions.filter((action) => action instanceof MonacoEditorDomainActionWithOptions), + withoutOptions: this.filterDisplayedActions(this.domainActions.filter((action) => !(action instanceof MonacoEditorDomainActionWithOptions))), + withOptions: this.filterDisplayedActions(this.domainActions.filter((action) => action instanceof MonacoEditorDomainActionWithOptions)), }, - lecture: this.lectureReferenceAction, - meta: this.metaActions, + lecture: this.filterDisplayedAction(this.lectureReferenceAction), + meta: this.filterDisplayedActions(this.metaActions), }; } + filterDisplayedActions(actions: T[]): T[] { + return actions.filter((action) => !action.hideInEditor); + } + + filterDisplayedAction(action?: T): T | undefined { + return action?.hideInEditor ? undefined : action; + } + ngAfterViewInit(): void { this.adjustEditorDimensions(); this.monacoEditor.setWordWrap(true); - this.monacoEditor.changeModel('markdown-content.custom-md', this._markdown, 'custom-md'); + this.monacoEditor.changeModel('markdown-content.custom-md', this._markdown ?? '', 'custom-md'); this.resizeObserver = new ResizeObserver(() => { this.adjustEditorDimensions(); }); @@ -232,6 +285,9 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie if (this.fileUploadFooter?.nativeElement) { this.resizeObserver.observe(this.fileUploadFooter.nativeElement); } + if (this.actionPalette?.nativeElement) { + this.resizeObserver.observe(this.actionPalette.nativeElement); + } [ this.defaultActions, this.headerActions?.actions ?? [], @@ -248,6 +304,10 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie } this.monacoEditor.registerAction(action); }); + + if (this.useDefaultMarkdownEditorOptions) { + this.monacoEditor.applyOptionPreset(DEFAULT_MARKDOWN_EDITOR_OPTIONS); + } } /** @@ -289,9 +349,9 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie * Adjusts the height of the element when the content height changes. * @param newContentHeight The new height of the content in the editor. */ - onContentHeightChanged(newContentHeight: number): void { + onContentHeightChanged(newContentHeight: number | undefined): void { if (this.linkEditorHeightToContentHeight) { - const totalHeight = newContentHeight + this.getElementClientHeight(this.fileUploadFooter) + this.getElementClientHeight(this.actionPalette); + const totalHeight = (newContentHeight ?? 0) + this.getElementClientHeight(this.fileUploadFooter) + this.getElementClientHeight(this.actionPalette); // Clamp the height so it is between the minimum and maximum height. this.targetWrapperHeight = Math.max(this.resizableMinHeight, Math.min(this.resizableMaxHeight, totalHeight)); } @@ -305,7 +365,7 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie const elementHeight = this.getElementClientHeight(this.isInitialHeightExternal() ? this.fullElement : this.wrapper); const fileUploadFooterHeight = this.getElementClientHeight(this.fileUploadFooter); const actionPaletteHeight = this.getElementClientHeight(this.actionPalette); - return elementHeight - fileUploadFooterHeight - actionPaletteHeight; + return elementHeight - fileUploadFooterHeight - actionPaletteHeight - BORDER_HEIGHT_OFFSET; } /** @@ -327,7 +387,9 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie * Adjust the dimensions of the editor to fit the available space. */ adjustEditorDimensions(): void { - this.monacoEditor.layoutWithFixedSize(this.getEditorWidth(), this.getEditorHeight()); + this.onContentHeightChanged(this.monacoEditor.getContentHeight()); + const editorHeight = this.getEditorHeight(); + this.monacoEditor.layoutWithFixedSize(this.getEditorWidth(), editorHeight); } /** @@ -335,13 +397,36 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie * @param event The event that contains the new active tab. */ onNavChanged(event: NgbNavChangeEvent) { - this.inPreviewMode = event.nextId === 'editor_preview'; - if (!this.inPreviewMode) { + this.inPreviewMode = event.nextId === this.TAB_PREVIEW; + this.inVisualMode = event.nextId === this.TAB_VISUAL; + this.inEditMode = event.nextId === this.TAB_EDIT; + if (this.inEditMode) { this.adjustEditorDimensions(); this.monacoEditor.focus(); - } else { + this.onEditSelect.emit(); + } else if (this.inPreviewMode) { this.onPreviewSelect.emit(); } + + // Some components need to know when the user leaves the visual tab, as it might make changes to the underlying data. + if (event.activeId === this.TAB_VISUAL) { + this.onLeaveVisualTab.emit(); + } + + // Parse the markdown when switching away from the edit tab or from visual to preview mode, as the visual mode may make changes to the markdown. + if (event.activeId === this.TAB_EDIT || (event.activeId === this.TAB_VISUAL && this.inPreviewMode)) { + this.parseMarkdown(); + } + } + + parseMarkdown(domainActionsToCheck: MonacoEditorDomainAction[] = this.domainActions): void { + if (this.showDefaultPreview) { + this.defaultPreviewHtml = this.artemisMarkdown.safeHtmlForMarkdown(this._markdown); + this.onDefaultPreviewHtmlChanged.emit(this.defaultPreviewHtml); + } + if (domainActionsToCheck.length && this._markdown) { + this.textWithDomainActionsFound.emit(parseMarkdownForDomainActions(this._markdown, domainActionsToCheck)); + } } /** @@ -434,7 +519,7 @@ export class MarkdownEditorMonacoComponent implements AfterContentInit, AfterVie * Enable the text field mode of the editor. This makes the editor look and behave like a normal text field. */ enableTextFieldMode(): void { - this.monacoEditor.enableTextFieldMode(); + this.monacoEditor.applyOptionPreset(COMMUNICATION_MARKDOWN_EDITOR_OPTIONS); } /** diff --git a/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-parsing.helper.ts b/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-parsing.helper.ts new file mode 100644 index 000000000000..058cacf8c2ba --- /dev/null +++ b/src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-parsing.helper.ts @@ -0,0 +1,61 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import { escapeStringForUseInRegex } from 'app/shared/util/global.utils'; +import { TextWithDomainAction } from './markdown-editor-monaco.component'; + +/** + * Searches for the domain actions in the given markdown text and returns the text split into parts, each part associated with the domain action it belongs to. + * Note that the text will be trimmed before being returned. + * @param markdown The markdown text to parse + * @param domainActions The domain actions to search for in the markdown + */ +export function parseMarkdownForDomainActions(markdown: string, domainActions: MonacoEditorDomainAction[]): TextWithDomainAction[] { + let remainingText = markdown; + const actionIdentifiersString = domainActions + .map((action) => action.getOpeningIdentifier()) + .map((identifier) => identifier.replace('[', '').replace(']', '')) + .map(escapeStringForUseInRegex) + .join('|'); + const textMappedToActionIdentifiers: TextWithDomainAction[] = []; + + /* + * The following regex is used to split the text into parts, each part associated with the domain action it belongs to. It is structured as follows: + * 1. (?= If an action is found, add the action identifier to the result of the split + * 2. \\[ look for the character '[' to determine the beginning of the action identifier + * 3. (${actionIdentifiersString}) look if after the '[' one of the element of actionIdentifiersString is contained + * 4. ] look for the character ']' to determine the end of the action identifier + * 5. ) ends the group + * Flags: + * - g: search in the whole string + * - m: match the regex over multiple lines + * - i: case-insensitive matching + */ + const regex = new RegExp(`(?=\\[(${actionIdentifiersString})])`, 'gmi'); + while (remainingText.length) { + const [textWithActionIdentifier] = remainingText.split(regex, 1); + remainingText = remainingText.substring(textWithActionIdentifier.length); + const textWithDomainAction = parseLineForDomainAction(textWithActionIdentifier.trim(), domainActions); + textMappedToActionIdentifiers.push(textWithDomainAction); + } + + return textMappedToActionIdentifiers; +} + +/** + * Checks if the given line contains any of the domain action identifiers and returns the text without the identifier along with the domain action it belongs to. + * @param text The text to parse + * @param domainActions The domain actions to search for in the text + */ +function parseLineForDomainAction(text: string, domainActions: MonacoEditorDomainAction[]): TextWithDomainAction { + for (const domainAction of domainActions) { + const possibleOpeningIdentifiers = [ + domainAction.getOpeningIdentifier(), + domainAction.getOpeningIdentifier().toLowerCase(), + domainAction.getOpeningIdentifier().toUpperCase(), + ]; + if (possibleOpeningIdentifiers.some((identifier) => text.indexOf(identifier) !== -1)) { + const trimmedLineWithoutIdentifier = possibleOpeningIdentifiers.reduce((line, identifier) => line.replace(identifier, ''), text).trim(); + return { text: trimmedLineWithoutIdentifier, action: domainAction }; + } + } + return { text: text.trim() }; +} diff --git a/src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.html b/src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.html index fb18ef521aa2..cd20f9b54615 100644 --- a/src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.html +++ b/src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.html @@ -12,6 +12,8 @@ [enableFileUpload]="false" [colorAction]="undefined" [enableResize]="false" + [showDefaultPreview]="false" + [useDefaultMarkdownEditorOptions]="false" [linkEditorHeightToContentHeight]="true" [initialEditorHeight]="editorHeight" [resizableMinHeight]="editorHeight" diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/communication/monaco-exercise-reference.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/communication/monaco-exercise-reference.action.ts index d9e2024b7513..014894dedd42 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/communication/monaco-exercise-reference.action.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/communication/monaco-exercise-reference.action.ts @@ -59,4 +59,8 @@ export class MonacoExerciseReferenceAction extends MonacoEditorDomainActionWithO super.dispose(); this.disposableCompletionProvider?.dispose(); } + + getOpeningIdentifier(): string { + return '[exercise]'; + } } diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action.ts new file mode 100644 index 000000000000..200a239de9ee --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action.ts @@ -0,0 +1,20 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import * as monaco from 'monaco-editor'; + +export class MonacoGradingCreditsAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-credits.action'; + static readonly IDENTIFIER = '[credits]'; + static readonly TEXT = '0'; + + constructor() { + super(MonacoGradingCreditsAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addCredits', undefined, undefined, true); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingCreditsAction.TEXT, true, false); + } + + getOpeningIdentifier(): string { + return MonacoGradingCreditsAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action.ts new file mode 100644 index 000000000000..02302850bca5 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action.ts @@ -0,0 +1,22 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from '../monaco-editor-domain-action.model'; +import { MonacoGradingInstructionAction } from './monaco-grading-instruction.action'; + +export class MonacoGradingCriterionAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-criterion.action'; + static readonly IDENTIFIER = '[criterion]'; + static readonly TEXT = 'Add criterion title (only visible to tutors)'; + + constructor(private readonly gradingInstructionAction: MonacoGradingInstructionAction) { + super(MonacoGradingCriterionAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addCriterion'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingCriterionAction.TEXT, false, false); + this.gradingInstructionAction.executeInCurrentEditor(); + } + + getOpeningIdentifier(): string { + return MonacoGradingCriterionAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action.ts new file mode 100644 index 000000000000..f04d861cb4d7 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action.ts @@ -0,0 +1,20 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; + +export class MonacoGradingDescriptionAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-description.action'; + static readonly IDENTIFIER = '[description]'; + static readonly TEXT = 'Add grading instruction here (only visible for tutors)'; + + constructor() { + super(MonacoGradingDescriptionAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addDescription', undefined, undefined, true); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingDescriptionAction.TEXT, true, false); + } + + getOpeningIdentifier(): string { + return MonacoGradingDescriptionAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action.ts new file mode 100644 index 000000000000..2dc1306eeffd --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action.ts @@ -0,0 +1,20 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; + +export class MonacoGradingFeedbackAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-feedback.action'; + static readonly IDENTIFIER = '[feedback]'; + static readonly TEXT = 'Add feedback for students here (visible for students)'; + + constructor() { + super(MonacoGradingFeedbackAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addFeedback', undefined, undefined, true); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingFeedbackAction.TEXT, true, false); + } + + getOpeningIdentifier(): string { + return MonacoGradingFeedbackAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action.ts new file mode 100644 index 000000000000..fa14b18da454 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action.ts @@ -0,0 +1,35 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from '../monaco-editor-domain-action.model'; +import { MonacoGradingCreditsAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action'; +import { MonacoGradingScaleAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action'; +import { MonacoGradingDescriptionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action'; +import { MonacoGradingFeedbackAction } from './monaco-grading-feedback.action'; +import { MonacoGradingUsageCountAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action'; + +export class MonacoGradingInstructionAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-instruction.action'; + static readonly IDENTIFIER = '[instruction]'; + + constructor( + private readonly creditsAction: MonacoGradingCreditsAction, + private readonly scaleAction: MonacoGradingScaleAction, + private readonly descriptionAction: MonacoGradingDescriptionAction, + private readonly feedbackAction: MonacoGradingFeedbackAction, + private readonly usageCountAction: MonacoGradingUsageCountAction, + ) { + super(MonacoGradingInstructionAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addInstruction'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, '', false, false); + this.creditsAction.executeInCurrentEditor(); + this.scaleAction.executeInCurrentEditor(); + this.descriptionAction.executeInCurrentEditor(); + this.feedbackAction.executeInCurrentEditor(); + this.usageCountAction.executeInCurrentEditor(); + } + + getOpeningIdentifier(): string { + return MonacoGradingInstructionAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action.ts new file mode 100644 index 000000000000..53e1bd2b9485 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action.ts @@ -0,0 +1,20 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import * as monaco from 'monaco-editor'; + +export class MonacoGradingScaleAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-scale.action'; + static readonly IDENTIFIER = '[gradingScale]'; + static readonly TEXT = 'Add instruction grading scale here (only visible for tutors)'; + + constructor() { + super(MonacoGradingScaleAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addScale', undefined, undefined, true); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingScaleAction.TEXT, true, false); + } + + getOpeningIdentifier(): string { + return MonacoGradingScaleAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action.ts new file mode 100644 index 000000000000..b68700d3e094 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action.ts @@ -0,0 +1,20 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; + +export class MonacoGradingUsageCountAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-grading-usage-count.action'; + static readonly IDENTIFIER = '[maxCountInScore]'; + static readonly TEXT = '0'; + + constructor() { + super(MonacoGradingUsageCountAction.ID, 'artemisApp.assessmentInstructions.instructions.editor.addUsageCount', undefined, undefined, true); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoGradingUsageCountAction.TEXT, true, false); + } + + getOpeningIdentifier(): string { + return MonacoGradingUsageCountAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-action.model.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-action.model.ts index 8a022d32b7fc..07c6c89e4ac5 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-action.model.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-action.model.ts @@ -11,6 +11,7 @@ export abstract class MonacoEditorAction implements monaco.editor.IActionDescrip keybindings?: number[]; icon?: IconDefinition; + readonly hideInEditor: boolean; /** * The disposable action that is returned by `editor.addAction`. This is required to unregister the action from the editor. @@ -28,12 +29,14 @@ export abstract class MonacoEditorAction implements monaco.editor.IActionDescrip * @param translationKey The translation key of the action label. * @param icon The icon to display in the editor toolbar, if any. * @param keybindings The keybindings to trigger the action, if any. + * @param hideInEditor Whether to hide the action in the editor toolbar. Defaults to false. */ - constructor(id: string, translationKey: string, icon?: IconDefinition, keybindings?: number[]) { + constructor(id: string, translationKey: string, icon?: IconDefinition, keybindings?: number[], hideInEditor?: boolean) { this.id = id; this.translationKey = translationKey; this.icon = icon; this.keybindings = keybindings; + this.hideInEditor = hideInEditor ?? false; } /** @@ -61,6 +64,7 @@ export abstract class MonacoEditorAction implements monaco.editor.IActionDescrip */ dispose(): void { this.disposableAction?.dispose(); + this.disposableAction = undefined; this._editor = undefined; } @@ -321,6 +325,10 @@ export abstract class MonacoEditorAction implements monaco.editor.IActionDescrip } } + getPosition(editor: monaco.editor.ICodeEditor): monaco.IPosition { + return editor.getPosition() ?? { lineNumber: 1, column: 1 }; + } + /** * Sets the selection of the given editor to the given range and reveals it in the center of the editor. * @param editor The editor to set the selection in. @@ -331,6 +339,24 @@ export abstract class MonacoEditorAction implements monaco.editor.IActionDescrip editor.revealRangeInCenter(selection); } + /** + * Clears the current selection in the given editor, but preserves the cursor position. + * @param editor The editor to clear the selection in. + */ + clearSelection(editor: monaco.editor.ICodeEditor): void { + const position = this.getPosition(editor); + this.setSelection(editor, new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column)); + } + + /** + * Adjusts the cursor position so it is at the end of the current line. + * @param editor The editor to adjust the cursor position in. + */ + moveCursorToEndOfLine(editor: monaco.editor.ICodeEditor): void { + const position: monaco.IPosition = { ...this.getPosition(editor), column: Number.POSITIVE_INFINITY }; + this.setPosition(editor, position); + } + /** * Toggles the fullscreen mode of the given element. If no element is provided, the editor's DOM node is used. * @param editor The editor to toggle the fullscreen mode for. diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model.ts index c914241efa76..2a9999e96fd2 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model.ts @@ -1,7 +1,36 @@ import { MonacoEditorAction } from './monaco-editor-action.model'; +import * as monaco from 'monaco-editor'; /** * Class representing domain actions for Artemis-specific use cases. - * TODO: In the future, each domain action should have its own logic and a unique identifier (e.g. multiple choice questions, drag and drop questions). */ -export abstract class MonacoEditorDomainAction extends MonacoEditorAction {} +export abstract class MonacoEditorDomainAction extends MonacoEditorAction { + abstract getOpeningIdentifier(): string; + + /** + * Inserts, below the current line, a new line with the domain action identifier and the given text. + * Afterward, if specified, sets the selection to cover exactly the provided text part. + * @param editor The editor in which to insert the text + * @param text The text to insert. Can be empty. + * @param indent Whether to indent the inserted text with a tab. + * @param updateSelection Whether to update the selection after inserting the text + */ + addTextWithDomainActionIdentifier(editor: monaco.editor.ICodeEditor, text: string, indent = false, updateSelection = true): void { + this.clearSelection(editor); + this.moveCursorToEndOfLine(editor); + const identifierWithText = text ? `${this.getOpeningIdentifier()} ${text}` : this.getOpeningIdentifier(); + const insertText = indent ? `\n\t${identifierWithText}` : `\n${identifierWithText}`; + this.insertTextAtPosition(editor, this.getPosition(editor), insertText); + if (updateSelection) { + const newPosition = this.getPosition(editor); + // Set the selection to cover exactly the text part + this.setSelection(editor, { + startLineNumber: newPosition.lineNumber, + endLineNumber: newPosition.lineNumber, + startColumn: newPosition.column - text.length, + endColumn: newPosition.column, + }); + } + editor.focus(); + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-formula.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-formula.action.ts index 4a605b733520..e7d5de9d0324 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-formula.action.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-formula.action.ts @@ -20,7 +20,11 @@ export class MonacoFormulaAction extends MonacoEditorDomainAction { * @param editor The editor in which to toggle formula text. */ run(editor: monaco.editor.ICodeEditor) { - this.toggleDelimiterAroundSelection(editor, FORMULA_OPEN_DELIMITER, FORMULA_CLOSE_DELIMITER, MonacoFormulaAction.DEFAULT_FORMULA); + this.toggleDelimiterAroundSelection(editor, this.getOpeningIdentifier(), FORMULA_CLOSE_DELIMITER, MonacoFormulaAction.DEFAULT_FORMULA); editor.focus(); } + + getOpeningIdentifier(): string { + return FORMULA_OPEN_DELIMITER; + } } diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-task.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-task.action.ts index 3a2aa120375a..e1fe3f87b53e 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-task.action.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-task.action.ts @@ -6,7 +6,8 @@ import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions */ export class MonacoTaskAction extends MonacoEditorDomainAction { static readonly ID = 'monaco-task.action'; - static readonly INSERT_TASK_TEXT = '[task][Task Short Description](testCaseName)\n'; + static readonly TEXT = '[Task Short Description](testCaseName)\n'; + constructor() { super(MonacoTaskAction.ID, 'artemisApp.programmingExercise.problemStatement.taskCommand', undefined, undefined); } @@ -16,7 +17,11 @@ export class MonacoTaskAction extends MonacoEditorDomainAction { * @param editor The editor in which to insert the task. */ run(editor: monaco.editor.ICodeEditor): void { - this.replaceTextAtCurrentSelection(editor, MonacoTaskAction.INSERT_TASK_TEXT); + this.replaceTextAtCurrentSelection(editor, `${this.getOpeningIdentifier()}${MonacoTaskAction.TEXT}`); editor.focus(); } + + getOpeningIdentifier(): string { + return '[task]'; + } } diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-test-case.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-test-case.action.ts index fc243b3943ee..e2d48c615709 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-test-case.action.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/monaco-test-case.action.ts @@ -74,4 +74,8 @@ export class MonacoTestCaseAction extends MonacoEditorDomainActionWithOptions { this.replaceTextAtCurrentSelection(editor, args?.selectedItem?.value ?? MonacoTestCaseAction.DEFAULT_INSERT_TEXT); editor.focus(); } + + getOpeningIdentifier(): string { + return '('; + } } diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action.ts new file mode 100644 index 000000000000..e8307539ec41 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action.ts @@ -0,0 +1,20 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import * as monaco from 'monaco-editor'; + +export class MonacoCorrectMultipleChoiceAnswerAction extends MonacoEditorDomainAction { + static readonly ID = 'artemisApp.multipleChoiceQuestion.editor.addCorrectAnswerOption'; + static readonly IDENTIFIER = '[correct]'; + static readonly TEXT = 'Enter a correct answer option here'; + + constructor() { + super(MonacoCorrectMultipleChoiceAnswerAction.ID, 'artemisApp.multipleChoiceQuestion.editor.addCorrectAnswerOption'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoCorrectMultipleChoiceAnswerAction.TEXT); + } + + getOpeningIdentifier(): string { + return MonacoCorrectMultipleChoiceAnswerAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action.ts new file mode 100644 index 000000000000..6cc078baa448 --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action.ts @@ -0,0 +1,20 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import * as monaco from 'monaco-editor'; + +export class MonacoQuizExplanationAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-quiz-explanation.action'; + static readonly IDENTIFIER = '[exp]'; + static readonly TEXT = 'Add an explanation here (only visible in feedback after quiz has ended)'; + + constructor() { + super(MonacoQuizExplanationAction.ID, 'artemisApp.multipleChoiceQuestion.editor.addExplanation'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoQuizExplanationAction.TEXT, true); + } + + getOpeningIdentifier(): string { + return MonacoQuizExplanationAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action.ts new file mode 100644 index 000000000000..29c320bf016b --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action.ts @@ -0,0 +1,20 @@ +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; +import * as monaco from 'monaco-editor'; + +export class MonacoQuizHintAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-quiz-hint.action'; + static readonly IDENTIFIER = '[hint]'; + static readonly TEXT = 'Add a hint here (visible during the quiz via ?-Button)'; + + constructor() { + super(MonacoQuizHintAction.ID, 'artemisApp.multipleChoiceQuestion.editor.addHint'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoQuizHintAction.TEXT, true); + } + + getOpeningIdentifier(): string { + return MonacoQuizHintAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action.ts b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action.ts new file mode 100644 index 000000000000..7c682072eb5a --- /dev/null +++ b/src/main/webapp/app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action.ts @@ -0,0 +1,20 @@ +import * as monaco from 'monaco-editor'; +import { MonacoEditorDomainAction } from 'app/shared/monaco-editor/model/actions/monaco-editor-domain-action.model'; + +export class MonacoWrongMultipleChoiceAnswerAction extends MonacoEditorDomainAction { + static readonly ID = 'monaco-incorrect-multiple-choice-answer.action'; + static readonly IDENTIFIER = '[wrong]'; + static readonly TEXT = 'Enter a wrong answer option here'; + + constructor() { + super(MonacoWrongMultipleChoiceAnswerAction.ID, 'artemisApp.multipleChoiceQuestion.editor.addInCorrectAnswerOption'); + } + + run(editor: monaco.editor.ICodeEditor): void { + this.addTextWithDomainActionIdentifier(editor, MonacoWrongMultipleChoiceAnswerAction.TEXT); + } + + getOpeningIdentifier(): string { + return MonacoWrongMultipleChoiceAnswerAction.IDENTIFIER; + } +} diff --git a/src/main/webapp/app/shared/monaco-editor/model/monaco-editor-option-preset.model.ts b/src/main/webapp/app/shared/monaco-editor/model/monaco-editor-option-preset.model.ts index b4ddcdc5a58d..e3470bdb6837 100644 --- a/src/main/webapp/app/shared/monaco-editor/model/monaco-editor-option-preset.model.ts +++ b/src/main/webapp/app/shared/monaco-editor/model/monaco-editor-option-preset.model.ts @@ -1,17 +1,19 @@ import * as monaco from 'monaco-editor'; +export type MonacoEditorOptions = monaco.editor.IEditorOptions; + /** * A preset of Monaco Editor options that can be applied to an editor for specific use cases, e.g. short answer quiz questions. * Presets are defined in the file monaco-editor-option.helper.ts. */ export class MonacoEditorOptionPreset { - constructor(private options: monaco.editor.IEditorOptions) {} + constructor(private options: MonacoEditorOptions) {} /** * Update the editor options with the preset options. * @param editor The editor to which the options should be applied. */ - apply(editor: monaco.editor.IStandaloneCodeEditor): void { + apply(editor: monaco.editor.ICodeEditor): void { editor.updateOptions(this.options); } } diff --git a/src/main/webapp/app/shared/monaco-editor/monaco-editor-option.helper.ts b/src/main/webapp/app/shared/monaco-editor/monaco-editor-option.helper.ts index d9c13af84836..ea36346ec1d3 100644 --- a/src/main/webapp/app/shared/monaco-editor/monaco-editor-option.helper.ts +++ b/src/main/webapp/app/shared/monaco-editor/monaco-editor-option.helper.ts @@ -1,4 +1,4 @@ -import { MonacoEditorOptionPreset } from 'app/shared/monaco-editor/model/monaco-editor-option-preset.model'; +import { MonacoEditorOptionPreset, MonacoEditorOptions } from 'app/shared/monaco-editor/model/monaco-editor-option-preset.model'; export const SHORT_ANSWER_QUIZ_QUESTION_EDITOR_OPTIONS = new MonacoEditorOptionPreset({ // Hide the gutter @@ -14,3 +14,40 @@ export const SHORT_ANSWER_QUIZ_QUESTION_EDITOR_OPTIONS = new MonacoEditorOptionP // Disable line highlighting renderLineHighlight: 'none', }); + +const defaultMarkdownOptions: MonacoEditorOptions = { + // Sets up the layout to make the editor look more like a text field (no line numbers, margin, or highlights). + lineNumbers: 'off', + glyphMargin: false, + folding: false, + lineDecorationsWidth: '1ch', + lineNumbersMinChars: 0, + padding: { + top: 5, + }, + renderLineHighlight: 'none', + // Only show scrollbars if required. + scrollbar: { + vertical: 'auto', + horizontal: 'auto', + }, + overviewRulerLanes: 0, + hideCursorInOverviewRuler: true, + // The suggestions from showWords are shared between editors of the same language, so we disable them. + suggest: { + showWords: false, + }, + // We use the 'simple' strategy for word wraps to prevent performance issues. This prevents us from switching to a different font as the lines would no longer break correctly. + wordWrap: 'on', + wrappingStrategy: 'simple', + selectionHighlight: false, + occurrencesHighlight: 'off', +}; + +export const DEFAULT_MARKDOWN_EDITOR_OPTIONS = new MonacoEditorOptionPreset(defaultMarkdownOptions); + +export const COMMUNICATION_MARKDOWN_EDITOR_OPTIONS = new MonacoEditorOptionPreset({ + ...defaultMarkdownOptions, + // Separates the editor suggest widget from the editor's layout. It will stick to the page, but it won't interfere with other elements. + fixedOverflowWidgets: true, +}); diff --git a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts index e7c5908d1a9a..1f28308ecb11 100644 --- a/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts +++ b/src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts @@ -100,8 +100,12 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { @Output() contentHeightChanged = new EventEmitter(); + @Output() + onBlurEditor = new EventEmitter(); + private contentHeightListener?: monaco.IDisposable; private textChangedListener?: monaco.IDisposable; + private blurEditorWidgetListener?: monaco.IDisposable; private textChangedEmitTimeout?: NodeJS.Timeout; ngOnInit(): void { @@ -120,6 +124,10 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { } }); + this.blurEditorWidgetListener = this._editor.onDidBlurEditorWidget(() => { + this.onBlurEditor.emit(); + }); + this.themeSubscription = this.themeService.getCurrentThemeObservable().subscribe((theme) => this.changeTheme(theme)); } @@ -129,6 +137,7 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { this.themeSubscription?.unsubscribe(); this.textChangedListener?.dispose(); this.contentHeightListener?.dispose(); + this.blurEditorWidgetListener?.dispose(); } private emitTextChangeEvent() { @@ -393,43 +402,6 @@ export class MonacoEditorComponent implements OnInit, OnDestroy { }); } - /** - * Enables a text field mode for the editor. This will make the editor look more like a text field and less like a code editor. - * In particular, line numbers, margins, and highlights will be disabled. - */ - enableTextFieldMode(): void { - this._editor.updateOptions({ - // Sets up the layout to make the editor look more like a text field (no line numbers, margin, or highlights). - lineNumbers: 'off', - glyphMargin: false, - folding: false, - lineDecorationsWidth: '1ch', - lineNumbersMinChars: 0, - padding: { - top: 5, - }, - renderLineHighlight: 'none', - selectionHighlight: false, - occurrencesHighlight: 'off', - // Only show scrollbars if required. - scrollbar: { - vertical: 'auto', - horizontal: 'auto', - }, - overviewRulerLanes: 0, - hideCursorInOverviewRuler: true, - // The suggestions from showWords are shared between editors of the same language. - suggest: { - showWords: false, - }, - // Separates the editor suggest widget from the editor's layout. It will stick to the page, but it won't interfere with other elements. - fixedOverflowWidgets: true, - // We use the 'simple' strategy for word wraps to prevent performance issues. This prevents us from switching to a different font as the lines would no longer break correctly. - wrappingStrategy: 'simple', - }); - this.setWordWrap(true); - } - /** * Applies the given options to the editor. * @param options The options to apply. diff --git a/src/test/javascript/spec/component/admin/legal-document-update.component.spec.ts b/src/test/javascript/spec/component/admin/legal-document-update.component.spec.ts index c9f6b2ebd4ee..bbec5290351b 100644 --- a/src/test/javascript/spec/component/admin/legal-document-update.component.spec.ts +++ b/src/test/javascript/spec/component/admin/legal-document-update.component.spec.ts @@ -6,7 +6,6 @@ import { UnsavedChangesWarningComponent } from 'app/admin/legal/unsaved-changes- import { ButtonComponent } from 'app/shared/components/button.component'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { ArtemisTestModule } from '../../test.module'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { JhiLanguageHelper } from 'app/core/language/language.helper'; import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal.service'; import { MockLanguageHelper } from '../../helpers/mocks/service/mock-translate.service'; @@ -19,6 +18,7 @@ import { ActivatedRoute, UrlSegment } from '@angular/router'; import { of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { PrivacyStatement } from 'app/entities/privacy-statement.model'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('LegalDocumentUpdateComponent', () => { let component: LegalDocumentUpdateComponent; @@ -35,7 +35,7 @@ describe('LegalDocumentUpdateComponent', () => { MockComponent(UnsavedChangesWarningComponent), MockComponent(ButtonComponent), MockDirective(TranslateDirective), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(ModePickerComponent), MockPipe(ArtemisTranslatePipe), ], @@ -117,7 +117,7 @@ describe('LegalDocumentUpdateComponent', () => { it('should correctly determine unsaved changes', () => { component.unsavedChanges = false; component.legalDocument.text = 'text'; - component.checkUnsavedChanges('changed text'); + component.onContentChanged('changed text'); expect(component.unsavedChanges).toBeTrue(); }); @@ -135,7 +135,7 @@ describe('LegalDocumentUpdateComponent', () => { updateFile = jest.spyOn(legalDocumentService, 'updateImprint').mockReturnValue(of(returnValue)); } component.markdownEditor.markdown = 'text'; - component.unsavedChanges = true; + component.onContentChanged('text'); const expected = new LegalDocument(documentType, LegalDocumentLanguage.GERMAN); expected.text = 'text'; fixture.detectChanges(); @@ -149,13 +149,12 @@ describe('LegalDocumentUpdateComponent', () => { expect(component.unsavedChanges).toBeFalse(); }), ); - it('should set the value of the markdown editor when switching to the edit mode if the language is changed while in preview mode', () => { + it('should set the value of the markdown editor when the language is changed while in preview mode', () => { setupRoutes(LegalDocumentType.PRIVACY_STATEMENT); const returnValue = new PrivacyStatement(LegalDocumentLanguage.GERMAN); returnValue.text = 'new content'; - const updateTextOnEditSelect = jest.spyOn(component, 'updateTextIfLanguageChangedInPreview').mockImplementation(); + const parseMarkdownStub = jest.spyOn(component.markdownEditor, 'parseMarkdown').mockImplementation(); component.markdownEditor.markdown = 'text'; - component.markdownEditor.previewMode = true; component.unsavedChanges = false; component.ngOnInit(); const loadFile = jest.spyOn(legalDocumentService, 'getPrivacyStatementForUpdate').mockReturnValue(of(returnValue)); @@ -164,7 +163,7 @@ describe('LegalDocumentUpdateComponent', () => { expect(loadFile).toHaveBeenCalledOnce(); expect(component.legalDocument.text).toBe('new content'); component.markdownEditor.onEditSelect.emit(); - expect(updateTextOnEditSelect).toHaveBeenCalledOnce(); + expect(parseMarkdownStub).toHaveBeenCalledOnce(); }); function setupRoutes(documentType: LegalDocumentType) { diff --git a/src/test/javascript/spec/component/competencies/competency-form.component.spec.ts b/src/test/javascript/spec/component/competencies/competency-form.component.spec.ts index ebe7506fbc81..40ef3c893792 100644 --- a/src/test/javascript/spec/component/competencies/competency-form.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/competency-form.component.spec.ts @@ -7,7 +7,7 @@ import { Competency, CompetencyTaxonomy } from 'app/entities/competency.model'; import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; import { Lecture } from 'app/entities/lecture.model'; import { LectureUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/lectureUnit.service'; -import { MockProvider } from 'ng-mocks'; +import { MockComponent, MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; @@ -17,6 +17,8 @@ import { CompetencyFormComponent } from 'app/course/competencies/forms/competenc import { CourseCompetencyFormData } from 'app/course/competencies/forms/course-competency-form.component'; import { By } from '@angular/platform-browser'; import { CommonCourseCompetencyFormComponent } from 'app/course/competencies/forms/common-course-competency-form.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; describe('CompetencyFormComponent', () => { let competencyFormComponentFixture: ComponentFixture; @@ -30,6 +32,10 @@ describe('CompetencyFormComponent', () => { declarations: [], providers: [MockProvider(CompetencyService), MockProvider(LectureUnitService), { provide: TranslateService, useClass: MockTranslateService }], }) + .overrideModule(ArtemisMarkdownEditorModule, { + remove: { exports: [MarkdownEditorMonacoComponent] }, + add: { exports: [MockComponent(MarkdownEditorMonacoComponent)], declarations: [MockComponent(MarkdownEditorMonacoComponent)] }, + }) .compileComponents() .then(() => { competencyFormComponentFixture = TestBed.createComponent(CompetencyFormComponent); diff --git a/src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts b/src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts index 9581c68a404a..88b261712f1f 100644 --- a/src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MockProvider } from 'ng-mocks'; +import { MockComponent, MockProvider } from 'ng-mocks'; import { AlertService } from 'app/core/util/alert.service'; import { ActivatedRoute, Router } from '@angular/router'; import { of } from 'rxjs'; @@ -15,6 +15,8 @@ import { MockRouter } from '../../helpers/mocks/mock-router'; import { CompetencyFormStubComponent } from './competency-form-stub.component'; import { ArtemisTestModule } from '../../test.module'; import { CompetencyFormComponent } from 'app/course/competencies/forms/competency/competency-form.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; describe('EditCompetencyComponent', () => { let editCompetencyComponentFixture: ComponentFixture; @@ -56,6 +58,10 @@ describe('EditCompetencyComponent', () => { ], schemas: [], }) + .overrideModule(ArtemisMarkdownEditorModule, { + remove: { exports: [MarkdownEditorMonacoComponent] }, + add: { exports: [MockComponent(MarkdownEditorMonacoComponent)], declarations: [MockComponent(MarkdownEditorMonacoComponent)] }, + }) .compileComponents() .then(() => { editCompetencyComponentFixture = TestBed.createComponent(EditCompetencyComponent); diff --git a/src/test/javascript/spec/component/competencies/edit-prerequisite.component.spec.ts b/src/test/javascript/spec/component/competencies/edit-prerequisite.component.spec.ts index 50e21caf9dfa..7e1009b2d1e8 100644 --- a/src/test/javascript/spec/component/competencies/edit-prerequisite.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/edit-prerequisite.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MockProvider } from 'ng-mocks'; +import { MockComponent, MockProvider } from 'ng-mocks'; import { AlertService } from 'app/core/util/alert.service'; import { ActivatedRoute, Router } from '@angular/router'; import { of } from 'rxjs'; @@ -16,6 +16,8 @@ import { EditPrerequisiteComponent } from 'app/course/competencies/edit/edit-pre import { PrerequisiteService } from 'app/course/competencies/prerequisite.service'; import { PrerequisiteFormComponent } from 'app/course/competencies/forms/prerequisite/prerequisite-form.component'; import { PrerequisiteFormStubComponent } from './prerequisite-form-stub.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; describe('EditPrerequisiteComponent', () => { let editPrerequisiteComponentFixture: ComponentFixture; @@ -57,6 +59,10 @@ describe('EditPrerequisiteComponent', () => { ], schemas: [], }) + .overrideModule(ArtemisMarkdownEditorModule, { + remove: { exports: [MarkdownEditorMonacoComponent] }, + add: { exports: [MockComponent(MarkdownEditorMonacoComponent)], declarations: [MockComponent(MarkdownEditorMonacoComponent)] }, + }) .compileComponents() .then(() => { editPrerequisiteComponentFixture = TestBed.createComponent(EditPrerequisiteComponent); diff --git a/src/test/javascript/spec/component/competencies/generate-competencies/competency-recommendation-detail.component.spec.ts b/src/test/javascript/spec/component/competencies/generate-competencies/competency-recommendation-detail.component.spec.ts index a2ee1c0c064b..b97f8099cd1d 100644 --- a/src/test/javascript/spec/component/competencies/generate-competencies/competency-recommendation-detail.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/generate-competencies/competency-recommendation-detail.component.spec.ts @@ -11,8 +11,8 @@ import { NgbCollapseMocksModule } from '../../../helpers/mocks/directive/ngbColl import { FeatureToggleDirective } from 'app/shared/feature-toggle/feature-toggle.directive'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { TaxonomySelectComponent } from 'app/course/competencies/taxonomy-select/taxonomy-select.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('CompetencyRecommendationDetailComponent', () => { let competencyRecommendationDetailComponentFixture: ComponentFixture; @@ -28,7 +28,7 @@ describe('CompetencyRecommendationDetailComponent', () => { MockDirective(TranslateDirective), MockPipe(ArtemisTranslatePipe), MockPipe(HtmlForMarkdownPipe), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(TaxonomySelectComponent), ], providers: [], diff --git a/src/test/javascript/spec/component/competencies/prerequisite-form.component.spec.ts b/src/test/javascript/spec/component/competencies/prerequisite-form.component.spec.ts index 3a3e852e4c39..4471d024976b 100644 --- a/src/test/javascript/spec/component/competencies/prerequisite-form.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/prerequisite-form.component.spec.ts @@ -6,7 +6,7 @@ import { CompetencyTaxonomy } from 'app/entities/competency.model'; import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; import { Lecture } from 'app/entities/lecture.model'; import { LectureUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/lectureUnit.service'; -import { MockProvider } from 'ng-mocks'; +import { MockComponent, MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; @@ -19,6 +19,8 @@ import { CommonCourseCompetencyFormComponent } from 'app/course/competencies/for import { PrerequisiteFormComponent } from 'app/course/competencies/forms/prerequisite/prerequisite-form.component'; import { PrerequisiteService } from 'app/course/competencies/prerequisite.service'; import { Prerequisite } from 'app/entities/prerequisite.model'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; +import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; describe('PrerequisiteFormComponent', () => { let prerequisiteFormComponentFixture: ComponentFixture; @@ -29,9 +31,12 @@ describe('PrerequisiteFormComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CompetencyFormComponent, ArtemisTestModule, ReactiveFormsModule, NgbDropdownModule], - declarations: [], providers: [MockProvider(PrerequisiteService), MockProvider(LectureUnitService), { provide: TranslateService, useClass: MockTranslateService }], }) + .overrideModule(ArtemisMarkdownEditorModule, { + remove: { exports: [MarkdownEditorMonacoComponent] }, + add: { exports: [MockComponent(MarkdownEditorMonacoComponent)], declarations: [MockComponent(MarkdownEditorMonacoComponent)] }, + }) .compileComponents() .then(() => { prerequisiteFormComponentFixture = TestBed.createComponent(PrerequisiteFormComponent); diff --git a/src/test/javascript/spec/component/course/course-update.component.spec.ts b/src/test/javascript/spec/component/course/course-update.component.spec.ts index 9566d806f9cf..2239ab6f91d1 100644 --- a/src/test/javascript/spec/component/course/course-update.component.spec.ts +++ b/src/test/javascript/spec/component/course/course-update.component.spec.ts @@ -43,7 +43,7 @@ import { ImageCropperModalComponent } from 'app/course/manage/image-cropper-moda import { FeatureToggle, FeatureToggleService } from 'app/shared/feature-toggle/feature-toggle.service'; import { MockFeatureToggleService } from '../../helpers/mocks/service/mock-feature-toggle.service'; -@Component({ selector: 'jhi-markdown-editor', template: '' }) +@Component({ selector: 'jhi-markdown-editor-monaco', template: '' }) class MarkdownEditorStubComponent { @Input() markdown: string; @Input() enableResize = false; diff --git a/src/test/javascript/spec/component/drag-and-drop-question/drag-and-drop-question-edit.component.spec.ts b/src/test/javascript/spec/component/drag-and-drop-question/drag-and-drop-question-edit.component.spec.ts index 2f5a5ee00a31..2a5d9fde2bb3 100644 --- a/src/test/javascript/spec/component/drag-and-drop-question/drag-and-drop-question-edit.component.spec.ts +++ b/src/test/javascript/spec/component/drag-and-drop-question/drag-and-drop-question-edit.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { NgModel } from '@angular/forms'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { NgbCollapse, NgbModal, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { DragAndDropMapping } from 'app/entities/quiz/drag-and-drop-mapping.model'; import { DragAndDropQuestion } from 'app/entities/quiz/drag-and-drop-question.model'; import { DragItem } from 'app/entities/quiz/drag-item.model'; @@ -13,10 +13,6 @@ import { QuizScoringInfoModalComponent } from 'app/exercises/quiz/manage/quiz-sc import { DragAndDropQuestionComponent } from 'app/exercises/quiz/shared/questions/drag-and-drop-question/drag-and-drop-question.component'; import { FileUploaderService } from 'app/shared/http/file-uploader.service'; import { SecuredImageComponent } from 'app/shared/image/secured-image.component'; -import { DomainCommand } from 'app/shared/markdown-editor/domainCommands/domainCommand'; -import { ExplanationCommand } from 'app/shared/markdown-editor/domainCommands/explanation.command'; -import { HintCommand } from 'app/shared/markdown-editor/domainCommands/hint.command'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal.service'; @@ -27,8 +23,9 @@ import { DragAndDropQuestionUtil } from 'app/exercises/quiz/shared/drag-and-drop import { ChangeDetectorRef } from '@angular/core'; import { clone } from 'lodash-es'; import { CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop'; -import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap'; -import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { MonacoQuizExplanationAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action'; +import { MonacoQuizHintAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action'; +import { MarkdownEditorMonacoComponent, TextWithDomainAction } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('DragAndDropQuestionEditComponent', () => { let fixture: ComponentFixture; @@ -75,7 +72,7 @@ describe('DragAndDropQuestionEditComponent', () => { DragAndDropQuestionEditComponent, MockPipe(ArtemisTranslatePipe), MockComponent(QuizScoringInfoModalComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(SecuredImageComponent), MockComponent(DragAndDropQuestionComponent), MockDirective(NgModel), @@ -603,36 +600,36 @@ describe('DragAndDropQuestionEditComponent', () => { expect(component.questionEditorText).toBe(newValue); }); - it('should detect domain commands', () => { + it('should detect domain actions', () => { component.question = new DragAndDropQuestion(); component.question.text = 'text'; component.question.explanation = 'explanation'; component.question.hint = 'hint'; - let domainCommand: [string, DomainCommand]; + let textWithDomainAction: TextWithDomainAction; // explanation - let command = new ExplanationCommand(); + let action = new MonacoQuizExplanationAction(); let text = 'take this as an explanationCommand'; - domainCommand = [text, command]; + textWithDomainAction = { text, action }; - component.domainCommandsFound([domainCommand]); + component.domainActionsFound([textWithDomainAction]); expect(component.question.explanation).toBe(text); // hint - command = new HintCommand(); + action = new MonacoQuizHintAction(); text = 'take this as a hintCommand'; - domainCommand = [text, command]; + textWithDomainAction = { text, action }; - component.domainCommandsFound([domainCommand]); + component.domainActionsFound([textWithDomainAction]); expect(component.question.hint).toBe(text); // text text = 'take this null as a command'; - domainCommand = [text, null as unknown as DomainCommand]; + textWithDomainAction = { text, action: undefined }; - component.domainCommandsFound([domainCommand]); + component.domainActionsFound([textWithDomainAction]); expect(component.question.text).toBe(text); }); diff --git a/src/test/javascript/spec/component/exam/exam-update.component.spec.ts b/src/test/javascript/spec/component/exam/exam-update.component.spec.ts index 3536693cbe09..6de1e1db5c13 100644 --- a/src/test/javascript/spec/component/exam/exam-update.component.spec.ts +++ b/src/test/javascript/spec/component/exam/exam-update.component.spec.ts @@ -19,7 +19,6 @@ import { Exam } from 'app/entities/exam.model'; import { Course, CourseInformationSharingConfiguration } from 'app/entities/course.model'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { GradingSystemService } from 'app/grading-system/grading-system.service'; @@ -43,6 +42,7 @@ import { DocumentationButtonComponent } from 'app/shared/components/documentatio import { TitleChannelNameComponent } from 'app/shared/form/title-channel-name/title-channel-name.component'; import { UMLDiagramType } from '@ls1intum/apollon'; import { TextExercise } from 'app/entities/text-exercise.model'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; @Component({ template: '', @@ -77,7 +77,7 @@ describe('ExamUpdateComponent', () => { declarations: [ ExamUpdateComponent, MockComponent(FormDateTimePickerComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(DataTableComponent), DummyComponent, MockPipe(ArtemisTranslatePipe), @@ -606,7 +606,7 @@ describe('ExamUpdateComponent', () => { ExamUpdateComponent, ExamExerciseImportComponent, MockComponent(FormDateTimePickerComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(DataTableComponent), DummyComponent, MockPipe(ArtemisTranslatePipe), diff --git a/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-modal.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-modal.component.spec.ts index 6e248103b247..6ab12448b3fb 100644 --- a/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-modal.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-modal.component.spec.ts @@ -7,9 +7,9 @@ import { AccountService } from 'app/core/auth/account.service'; import { By } from '@angular/platform-browser'; import { MockComponent } from 'ng-mocks'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ExamLiveEventComponent } from 'app/exam/shared/events/exam-live-event.component'; import { ExamWideAnnouncementEvent } from 'app/exam/participate/exam-participation-live-events.service'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('ExamLiveAnnouncementCreateModalComponent', () => { let component: ExamLiveAnnouncementCreateModalComponent; @@ -19,7 +19,12 @@ describe('ExamLiveAnnouncementCreateModalComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ExamLiveAnnouncementCreateModalComponent, MockComponent(FaIconComponent), MockComponent(MarkdownEditorComponent), MockComponent(ExamLiveEventComponent)], + declarations: [ + ExamLiveAnnouncementCreateModalComponent, + MockComponent(FaIconComponent), + MockComponent(MarkdownEditorMonacoComponent), + MockComponent(ExamLiveEventComponent), + ], providers: [ { provide: NgbActiveModal, useValue: { dismiss: jest.fn() } }, { provide: ExamManagementService, useValue: { createAnnouncement: jest.fn() } }, diff --git a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts index 038a9cc515ef..2af4e435afaf 100644 --- a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts +++ b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts @@ -11,7 +11,6 @@ import { HelpIconComponent } from 'app/shared/components/help-icon.component'; import { ExerciseHintService } from 'app/exercises/shared/exercise-hint/shared/exercise-hint.service'; import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; import { ActivatedRoute } from '@angular/router'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; @@ -25,6 +24,7 @@ import { IrisSettings } from 'app/entities/iris/settings/iris-settings.model'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { PROFILE_IRIS } from 'app/app.constants'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('ExerciseHint Management Update Component', () => { let comp: ExerciseHintUpdateComponent; @@ -52,7 +52,7 @@ describe('ExerciseHint Management Update Component', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ imports: [ArtemisTestModule, FormsModule], - declarations: [ExerciseHintUpdateComponent, MockComponent(MarkdownEditorComponent), MockComponent(HelpIconComponent)], + declarations: [ExerciseHintUpdateComponent, MockComponent(MarkdownEditorMonacoComponent), MockComponent(HelpIconComponent)], providers: [ FormBuilder, MockProvider(ProgrammingExerciseService), diff --git a/src/test/javascript/spec/component/exercises/quiz/manage/re-evaluate/re-evaluate-multiple-choice-question.component.spec.ts b/src/test/javascript/spec/component/exercises/quiz/manage/re-evaluate/re-evaluate-multiple-choice-question.component.spec.ts index 7c65c546617a..67de3457a999 100644 --- a/src/test/javascript/spec/component/exercises/quiz/manage/re-evaluate/re-evaluate-multiple-choice-question.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/quiz/manage/re-evaluate/re-evaluate-multiple-choice-question.component.spec.ts @@ -4,13 +4,13 @@ import { MockComponent, MockDirective, MockModule, MockPipe, MockProvider } from import { ArtemisTestModule } from '../../../../../test.module'; import { ReEvaluateMultipleChoiceQuestionComponent } from 'app/exercises/quiz/manage/re-evaluate/multiple-choice-question/re-evaluate-multiple-choice-question.component'; import { MultipleChoiceQuestionEditComponent } from 'app/exercises/quiz/manage/multiple-choice-question/multiple-choice-question-edit.component'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { NgModel } from '@angular/forms'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { Directive, Input } from '@angular/core'; import { MultipleChoiceQuestion } from 'app/entities/quiz/multiple-choice-question.model'; import { AnswerOption } from 'app/entities/quiz/answer-option.model'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; // eslint-disable-next-line @angular-eslint/directive-selector @Directive({ selector: '[sortableData]' }) @@ -31,7 +31,7 @@ describe('ReEvaluateMultipleChoiceQuestionComponent', () => { declarations: [ ReEvaluateMultipleChoiceQuestionComponent, MockComponent(MultipleChoiceQuestionEditComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockDirective(NgModel), MockDirective(MockSortableDataDirective), MockPipe(ArtemisTranslatePipe), diff --git a/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts index 0dfc849da228..32f0d6889eec 100644 --- a/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts @@ -12,7 +12,7 @@ import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { MockRouter } from '../../../helpers/mocks/mock-router'; import { CompetencySelectionComponent } from 'app/shared/competency-selection/competency-selection.component'; -@Component({ selector: 'jhi-markdown-editor', template: '' }) +@Component({ selector: 'jhi-markdown-editor-monaco', template: '' }) class MarkdownEditorStubComponent { @Input() markdown: string; @Input() enableResize = false; diff --git a/src/test/javascript/spec/component/lecture/lecture-update.component.spec.ts b/src/test/javascript/spec/component/lecture/lecture-update.component.spec.ts index c53c66a2034f..03be222b4cb4 100644 --- a/src/test/javascript/spec/component/lecture/lecture-update.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/lecture-update.component.spec.ts @@ -10,7 +10,6 @@ import { LectureUpdateComponent } from 'app/lecture/lecture-update.component'; import { LectureService } from 'app/lecture/lecture.service'; import { LectureUpdateWizardComponent } from 'app/lecture/wizard-mode/lecture-update-wizard.component'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; @@ -23,6 +22,7 @@ import { MockTranslateService } from '../../helpers/mocks/service/mock-translate import { ArtemisTestModule } from '../../test.module'; import { DocumentationButtonComponent } from 'app/shared/components/documentation-button/documentation-button.component'; import { LectureTitleChannelNameComponent } from 'app/lecture/lecture-title-channel-name.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('LectureUpdateComponent', () => { let lectureUpdateWizardComponentFixture: ComponentFixture; @@ -51,7 +51,7 @@ describe('LectureUpdateComponent', () => { MockComponent(LectureTitleChannelNameComponent), MockComponent(LectureUpdateWizardComponent), MockComponent(FormDateTimePickerComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(DocumentationButtonComponent), MockPipe(ArtemisTranslatePipe), MockPipe(ArtemisDatePipe), diff --git a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-title.component.spec.ts b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-title.component.spec.ts index 2d40c01a5b50..36701004edbb 100644 --- a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-title.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-title.component.spec.ts @@ -1,10 +1,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { LectureUpdateWizardTitleComponent } from 'app/lecture/wizard-mode/lecture-wizard-title.component'; import { Lecture } from 'app/entities/lecture.model'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { MockComponent } from 'ng-mocks'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { LectureTitleChannelNameComponent } from 'app/lecture/lecture-title-channel-name.component'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('LectureWizardTitleComponent', () => { let wizardTitleComponentFixture: ComponentFixture; @@ -13,7 +13,7 @@ describe('LectureWizardTitleComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ReactiveFormsModule, FormsModule], - declarations: [LectureUpdateWizardTitleComponent, MockComponent(MarkdownEditorComponent), MockComponent(LectureTitleChannelNameComponent)], + declarations: [LectureUpdateWizardTitleComponent, MockComponent(MarkdownEditorMonacoComponent), MockComponent(LectureTitleChannelNameComponent)], providers: [], schemas: [], }) diff --git a/src/test/javascript/spec/component/markdown-editor/markdown-editor-monaco.component.spec.ts b/src/test/javascript/spec/component/markdown-editor/markdown-editor-monaco.component.spec.ts index 2e0ea029b664..6e9ec8921a96 100644 --- a/src/test/javascript/spec/component/markdown-editor/markdown-editor-monaco.component.spec.ts +++ b/src/test/javascript/spec/component/markdown-editor/markdown-editor-monaco.component.spec.ts @@ -21,6 +21,7 @@ import { MonacoTestCaseAction } from 'app/shared/monaco-editor/model/actions/mon import { MonacoTaskAction } from 'app/shared/monaco-editor/model/actions/monaco-task.action'; import { MonacoFullscreenAction } from 'app/shared/monaco-editor/model/actions/monaco-fullscreen.action'; import { MonacoEditorOptionPreset } from 'app/shared/monaco-editor/model/monaco-editor-option-preset.model'; +import { COMMUNICATION_MARKDOWN_EDITOR_OPTIONS } from 'app/shared/monaco-editor/monaco-editor-option.helper'; describe('MarkdownEditorMonacoComponent', () => { let fixture: ComponentFixture; @@ -86,11 +87,28 @@ describe('MarkdownEditorMonacoComponent', () => { fixture.detectChanges(); const adjustEditorDimensionsSpy = jest.spyOn(comp, 'adjustEditorDimensions'); const focusSpy = jest.spyOn(comp.monacoEditor, 'focus'); - comp.onNavChanged({ nextId: 'editor', activeId: 'editor_preview', preventDefault: jest.fn() }); + comp.onNavChanged({ nextId: MarkdownEditorMonacoComponent.TAB_EDIT, activeId: MarkdownEditorMonacoComponent.TAB_PREVIEW, preventDefault: jest.fn() }); expect(adjustEditorDimensionsSpy).toHaveBeenCalledOnce(); expect(focusSpy).toHaveBeenCalledOnce(); }); + it('should emit when leaving the visual tab', () => { + const emitSpy = jest.spyOn(comp.onLeaveVisualTab, 'emit'); + fixture.detectChanges(); + comp.onNavChanged({ nextId: MarkdownEditorMonacoComponent.TAB_EDIT, activeId: MarkdownEditorMonacoComponent.TAB_VISUAL, preventDefault: jest.fn() }); + expect(emitSpy).toHaveBeenCalledOnce(); + }); + + it.each([ + { tab: MarkdownEditorMonacoComponent.TAB_EDIT, flags: [true, false, false] }, + { tab: MarkdownEditorMonacoComponent.TAB_PREVIEW, flags: [false, true, false] }, + { tab: MarkdownEditorMonacoComponent.TAB_VISUAL, flags: [false, false, true] }, + ])(`should set the correct flags when navigating to $tab`, ({ tab, flags }) => { + fixture.detectChanges(); + comp.onNavChanged({ nextId: tab, activeId: MarkdownEditorMonacoComponent.TAB_EDIT, preventDefault: jest.fn() }); + expect([comp.inEditMode, comp.inPreviewMode, comp.inVisualMode]).toEqual(flags); + }); + it('should embed manually uploaded files', () => { const embedFilesStub = jest.spyOn(comp, 'embedFiles').mockImplementation(); fixture.detectChanges(); @@ -213,11 +231,9 @@ describe('MarkdownEditorMonacoComponent', () => { it('should react to content height changes if the height is linked to the editor', () => { comp.linkEditorHeightToContentHeight = true; - comp.initialEditorHeight = MarkdownEditorHeight.MEDIUM; - comp.resizableMinHeight = MarkdownEditorHeight.SMALL; comp.resizableMaxHeight = MarkdownEditorHeight.LARGE; fixture.detectChanges(); - expect(comp.targetWrapperHeight).toBe(MarkdownEditorHeight.MEDIUM); + expect(comp.targetWrapperHeight).toBe(MarkdownEditorHeight.SMALL); comp.onContentHeightChanged(1500); expect(comp.targetWrapperHeight).toBe(MarkdownEditorHeight.LARGE); comp.onContentHeightChanged(20); @@ -235,11 +251,11 @@ describe('MarkdownEditorMonacoComponent', () => { expect(comp.targetWrapperHeight).toBe(300 - wrapperTop - dragElemHeight / 2); }); - it('should forward enableTextFieldMode call', () => { + it('should use the correct options to enable text field mode', () => { fixture.detectChanges(); - const setTextFieldModeSpy = jest.spyOn(comp.monacoEditor, 'enableTextFieldMode'); + const applySpy = jest.spyOn(comp.monacoEditor, 'applyOptionPreset'); comp.enableTextFieldMode(); - expect(setTextFieldModeSpy).toHaveBeenCalledOnce(); + expect(applySpy).toHaveBeenCalledExactlyOnceWith(COMMUNICATION_MARKDOWN_EDITOR_OPTIONS); }); it('should apply option presets to the editor', () => { diff --git a/src/test/javascript/spec/component/markdown-editor/markdown-editor-parsing.helper.spec.ts b/src/test/javascript/spec/component/markdown-editor/markdown-editor-parsing.helper.spec.ts new file mode 100644 index 000000000000..99b9ec09559f --- /dev/null +++ b/src/test/javascript/spec/component/markdown-editor/markdown-editor-parsing.helper.spec.ts @@ -0,0 +1,51 @@ +import { parseMarkdownForDomainActions } from 'app/shared/markdown-editor/monaco/markdown-editor-parsing.helper'; +import { MonacoGradingDescriptionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action'; +import { MonacoGradingFeedbackAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action'; + +describe('MarkdownEditorParsingHelper', () => { + it('should parse markdown without domain action identifiers', () => { + const markdown = 'This is some text that uses no domain action identifiers.'; + const result = parseMarkdownForDomainActions(markdown, []); + expect(result).toEqual([{ text: markdown, action: undefined }]); + }); + + it('should parse single-line text with one domain action identifier', () => { + const action = new MonacoGradingDescriptionAction(); + const markdown = 'This is some text. [description] This is a description.'; + const result = parseMarkdownForDomainActions(markdown, [action]); + expect(result).toEqual([ + { text: 'This is some text.', action: undefined }, + { text: 'This is a description.', action }, + ]); + }); + + it('should parse single-line text with multiple domain action identifiers', () => { + const descriptionAction = new MonacoGradingDescriptionAction(); + const feedbackAction = new MonacoGradingFeedbackAction(); + const markdown = 'This is some text. [description] This is a description. [feedback] This is some feedback.'; + const result = parseMarkdownForDomainActions(markdown, [descriptionAction, feedbackAction]); + expect(result).toEqual([ + { text: 'This is some text.', action: undefined }, + { text: 'This is a description.', action: descriptionAction }, + { text: 'This is some feedback.', action: feedbackAction }, + ]); + }); + + it('should parse multi-line text without domain action identifiers', () => { + const markdown = 'This is some text that uses no domain action identifiers.\nThis is a second line.'; + const result = parseMarkdownForDomainActions(markdown, []); + expect(result).toEqual([{ text: markdown, action: undefined }]); + }); + + it('should parse multi-line text with multiple domain action identifiers', () => { + const descriptionAction = new MonacoGradingDescriptionAction(); + const feedbackAction = new MonacoGradingFeedbackAction(); + const markdown = 'This is some text. [description] This is a description.\n [feedback] This is some feedback.'; + const result = parseMarkdownForDomainActions(markdown, [descriptionAction, feedbackAction]); + expect(result).toEqual([ + { text: 'This is some text.', action: undefined }, + { text: 'This is a description.', action: descriptionAction }, + { text: 'This is some feedback.', action: feedbackAction }, + ]); + }); +}); diff --git a/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question-edit.component.spec.ts b/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question-edit.component.spec.ts index 04a5b5b9e616..763122daee76 100644 --- a/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question-edit.component.spec.ts +++ b/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question-edit.component.spec.ts @@ -7,12 +7,6 @@ import { QuizScoringInfoModalComponent } from 'app/exercises/quiz/manage/quiz-sc import { DragAndDropQuestionComponent } from 'app/exercises/quiz/shared/questions/drag-and-drop-question/drag-and-drop-question.component'; import { MultipleChoiceQuestionComponent } from 'app/exercises/quiz/shared/questions/multiple-choice-question/multiple-choice-question.component'; import { SecuredImageComponent } from 'app/shared/image/secured-image.component'; -import { CorrectOptionCommand } from 'app/shared/markdown-editor/domainCommands/correctOptionCommand'; -import { ExplanationCommand } from 'app/shared/markdown-editor/domainCommands/explanation.command'; -import { HintCommand } from 'app/shared/markdown-editor/domainCommands/hint.command'; -import { IncorrectOptionCommand } from 'app/shared/markdown-editor/domainCommands/incorrectOptionCommand'; -import { TestCaseCommand } from 'app/shared/markdown-editor/domainCommands/programming-exercise/testCase.command'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { DragDropModule } from '@angular/cdk/drag-drop'; @@ -21,6 +15,12 @@ import { NgbCollapseMocksModule } from '../../helpers/mocks/directive/ngbCollaps import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { MultipleChoiceVisualQuestionComponent } from 'app/exercises/quiz/shared/questions/multiple-choice-question/multiple-choice-visual-question.component'; import { ScoringType } from 'app/entities/quiz/quiz-question.model'; +import { MonacoQuizHintAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action'; +import { MonacoQuizExplanationAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action'; +import { MonacoWrongMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action'; +import { MonacoCorrectMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action'; +import { MonacoTestCaseAction } from 'app/shared/monaco-editor/model/actions/monaco-test-case.action'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('MultipleChoiceQuestionEditComponent', () => { let fixture: ComponentFixture; @@ -47,7 +47,7 @@ describe('MultipleChoiceQuestionEditComponent', () => { MultipleChoiceQuestionEditComponent, MockPipe(ArtemisTranslatePipe), MockComponent(QuizScoringInfoModalComponent), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(SecuredImageComponent), MockComponent(DragAndDropQuestionComponent), MockComponent(MultipleChoiceQuestionComponent), @@ -91,12 +91,12 @@ describe('MultipleChoiceQuestionEditComponent', () => { }); it('should parse answer options but not question titles', () => { - component.domainCommandsFound([ - ['text1', new TestCaseCommand()], - ['text2', new CorrectOptionCommand()], - ['text3', new IncorrectOptionCommand()], - ['text4', new ExplanationCommand()], - ['text5', new HintCommand()], + component.domainActionsFound([ + { text: 'text1', action: new MonacoTestCaseAction() }, + { text: 'text2', action: new MonacoCorrectMultipleChoiceAnswerAction() }, + { text: 'text3', action: new MonacoWrongMultipleChoiceAnswerAction() }, + { text: 'text4', action: new MonacoQuizExplanationAction() }, + { text: 'text5', action: new MonacoQuizHintAction() }, ]); const expected: MultipleChoiceQuestion = { @@ -129,12 +129,12 @@ describe('MultipleChoiceQuestionEditComponent', () => { }); it('should parse answer options with question titles', () => { - component.domainCommandsFound([ - ['text1', new ExplanationCommand()], - ['text2', new HintCommand()], - ['text3', new TestCaseCommand()], - ['text4', new CorrectOptionCommand()], - ['text5', new IncorrectOptionCommand()], + component.domainActionsFound([ + { text: 'text1', action: new MonacoQuizExplanationAction() }, + { text: 'text2', action: new MonacoQuizHintAction() }, + { text: 'text3', action: new MonacoTestCaseAction() }, + { text: 'text4', action: new MonacoCorrectMultipleChoiceAnswerAction() }, + { text: 'text5', action: new MonacoWrongMultipleChoiceAnswerAction() }, ]); const expected: MultipleChoiceQuestion = { @@ -165,7 +165,7 @@ describe('MultipleChoiceQuestionEditComponent', () => { }); it('should parse question titles', () => { - component.domainCommandsFound([['text1', null]]); + component.domainActionsFound([{ text: 'text1', action: undefined }]); const expected: MultipleChoiceQuestion = { id: question.id, @@ -183,8 +183,8 @@ describe('MultipleChoiceQuestionEditComponent', () => { expect(component.showMultipleChoiceQuestionPreview).toBeTrue(); }); - it('should find no domain commands', () => { - component.domainCommandsFound([]); + it('should find no domain actions', () => { + component.domainActionsFound([]); expectCleanupQuestion(); expect(component.showMultipleChoiceQuestionPreview).toBeTrue(); diff --git a/src/test/javascript/spec/component/shared/grading-instructions-details.component.spec.ts b/src/test/javascript/spec/component/shared/grading-instructions-details.component.spec.ts index c5f89566b009..ae00000ae4b6 100644 --- a/src/test/javascript/spec/component/shared/grading-instructions-details.component.spec.ts +++ b/src/test/javascript/spec/component/shared/grading-instructions-details.component.spec.ts @@ -4,20 +4,20 @@ import { Exercise } from 'app/entities/exercise.model'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; import { GradingInstruction } from 'app/exercises/shared/structured-grading-criterion/grading-instruction.model'; import { GradingInstructionsDetailsComponent } from 'app/exercises/shared/structured-grading-criterion/grading-instructions-details/grading-instructions-details.component'; -import { CreditsCommand } from 'app/shared/markdown-editor/domainCommands/credits.command'; -import { DomainCommand } from 'app/shared/markdown-editor/domainCommands/domainCommand'; -import { FeedbackCommand } from 'app/shared/markdown-editor/domainCommands/feedback.command'; -import { GradingCriterionCommand } from 'app/shared/markdown-editor/domainCommands/gradingCriterionCommand'; -import { GradingInstructionCommand } from 'app/shared/markdown-editor/domainCommands/gradingInstruction.command'; -import { GradingScaleCommand } from 'app/shared/markdown-editor/domainCommands/gradingScaleCommand'; -import { InstructionDescriptionCommand } from 'app/shared/markdown-editor/domainCommands/instructionDescription.command'; -import { UsageCountCommand } from 'app/shared/markdown-editor/domainCommands/usageCount.command'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { ArtemisTestModule } from '../../test.module'; - -describe('Grading Instructions Management Component', () => { +import { MonacoGradingInstructionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action'; +import { MonacoGradingCreditsAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action'; +import { MonacoGradingScaleAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action'; +import { MonacoGradingDescriptionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action'; +import { MonacoGradingFeedbackAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action'; +import { MonacoGradingUsageCountAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action'; +import { MonacoGradingCriterionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action'; +import { TextWithDomainAction } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; + +describe('GradingInstructionsDetailsComponent', () => { let component: GradingInstructionsDetailsComponent; let fixture: ComponentFixture; let gradingInstruction: GradingInstruction; @@ -28,22 +28,13 @@ describe('Grading Instructions Management Component', () => { const backupExercise = { id: 1 } as Exercise; const criterionMarkdownText = - '[criterion]' + - 'testCriteria' + - '\n' + - '\t' + - '[instruction]\n' + - '\t' + - '[credits]' + - ' 1\n' + - '\t' + - '[gradingScale] scale\n' + - '\t' + - '[description] description\n' + - '\t' + - '[feedback] feedback\n' + - '\t' + - '[maxCountInScore] 0\n\n'; + '[criterion] testCriteria\n' + + '\t[instruction]\n' + + '\t[credits] 1\n' + + '\t[gradingScale] scale\n' + + '\t[description] description\n' + + '\t[feedback] feedback\n' + + '\t[maxCountInScore] 0\n\n'; beforeEach(() => { TestBed.configureTestingModule({ @@ -146,10 +137,10 @@ describe('Grading Instructions Management Component', () => { it('should change grading instruction', () => { const newDescription = 'new text'; - const domainCommands = [[newDescription, new InstructionDescriptionCommand()]] as [string, DomainCommand | null][]; + const domainActions = [{ text: newDescription, action: new MonacoGradingDescriptionAction() }] as TextWithDomainAction[]; component.exercise.gradingCriteria = [gradingCriterion]; - component.onInstructionChange(domainCommands, gradingInstruction); + component.onInstructionChange(domainActions, gradingInstruction); fixture.detectChanges(); expect(component.exercise.gradingCriteria[0].structuredGradingInstructions[0].instructionDescription).toEqual(newDescription); @@ -165,25 +156,38 @@ describe('Grading Instructions Management Component', () => { it('should set grading instruction text for exercise', () => { const markdownText = 'new text'; - const domainCommands = [[markdownText, null]] as [string, DomainCommand | null][]; + const domainActions = [{ text: markdownText, action: undefined }] as TextWithDomainAction[]; - component.setExerciseGradingInstructionText(domainCommands); + component.setExerciseGradingInstructionText(domainActions); fixture.detectChanges(); expect(component.exercise.gradingInstructions).toEqual(markdownText); }); - it('should set grading instruction without criterion command when markdown-change triggered', () => { - const domainCommands = [ - ['', new GradingInstructionCommand()], - ['1', new CreditsCommand()], - ['scale', new GradingScaleCommand()], - ['description', new InstructionDescriptionCommand()], - ['feedback', new FeedbackCommand()], - ['0', new UsageCountCommand()], - ] as [string, DomainCommand | null][]; + const getDomainActionArray = () => { + const creditsAction = new MonacoGradingCreditsAction(); + const scaleAction = new MonacoGradingScaleAction(); + const descriptionAction = new MonacoGradingDescriptionAction(); + const feedbackAction = new MonacoGradingFeedbackAction(); + const usageCountAction = new MonacoGradingUsageCountAction(); + const instructionAction = new MonacoGradingInstructionAction(creditsAction, scaleAction, descriptionAction, feedbackAction, usageCountAction); + const criterionAction = new MonacoGradingCriterionAction(instructionAction); + + return [ + { text: 'testCriteria', action: criterionAction }, + { text: '', action: instructionAction }, + { text: '1', action: creditsAction }, + { text: 'scale', action: scaleAction }, + { text: 'description', action: descriptionAction }, + { text: 'feedback', action: feedbackAction }, + { text: '0', action: usageCountAction }, + ] as TextWithDomainAction[]; + }; - component.domainCommandsFound(domainCommands); + it('should set grading instruction without criterion action when markdown-change triggered', () => { + const domainActionsWithoutCriterion = getDomainActionArray().slice(1); + + component.onDomainActionsFound(domainActionsWithoutCriterion); fixture.detectChanges(); expect(component.exercise.gradingCriteria).toBeDefined(); @@ -191,18 +195,10 @@ describe('Grading Instructions Management Component', () => { expect(gradingCriteria.structuredGradingInstructions[0]).toEqual(gradingInstructionWithoutId); }); - it('should set grading instruction with criterion command when markdown-change triggered', () => { - const domainCommands = [ - ['testCriteria', new GradingCriterionCommand()], - ['', new GradingInstructionCommand()], - ['1', new CreditsCommand()], - ['scale', new GradingScaleCommand()], - ['description', new InstructionDescriptionCommand()], - ['feedback', new FeedbackCommand()], - ['0', new UsageCountCommand()], - ] as [string, DomainCommand | null][]; - - component.domainCommandsFound(domainCommands); + it('should set grading instruction with criterion action when markdown-change triggered', () => { + const domainActions = getDomainActionArray(); + + component.onDomainActionsFound(domainActions); fixture.detectChanges(); expect(component.exercise.gradingCriteria).toBeDefined(); diff --git a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action-quiz.integration.spec.ts b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action-quiz.integration.spec.ts index 4ef09a0bed8c..482467968cdb 100644 --- a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action-quiz.integration.spec.ts +++ b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action-quiz.integration.spec.ts @@ -5,6 +5,10 @@ import { MonacoEditorModule } from 'app/shared/monaco-editor/monaco-editor.modul import { MockResizeObserver } from '../../../helpers/mocks/service/mock-resize-observer'; import { MonacoInsertShortAnswerOptionAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-insert-short-answer-option.action'; import { MonacoInsertShortAnswerSpotAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-insert-short-answer-spot.action'; +import { MonacoWrongMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-wrong-multiple-choice-answer.action'; +import { MonacoCorrectMultipleChoiceAnswerAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-correct-multiple-choice-answer.action'; +import { MonacoQuizExplanationAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-explanation.action'; +import { MonacoQuizHintAction } from 'app/shared/monaco-editor/model/actions/quiz/monaco-quiz-hint.action'; describe('MonacoEditorActionQuizIntegration', () => { let fixture: ComponentFixture; @@ -135,4 +139,40 @@ describe('MonacoEditorActionQuizIntegration', () => { expect(comp.getText()).toBe(questionText + '[-spot 1]' + `\n\n\n[-option 1] ${MonacoInsertShortAnswerOptionAction.DEFAULT_TEXT}`); }); }); + + describe('Multiple Choice answer options', () => { + it('should insert a wrong MC option', () => { + comp.triggerKeySequence('This is a question that needs some options.'); + const action = new MonacoWrongMultipleChoiceAnswerAction(); + comp.registerAction(action); + action.executeInCurrentEditor(); + expect(comp.getText()).toBe('This is a question that needs some options.\n[wrong] Enter a wrong answer option here'); + }); + + it('should insert a correct MC option', () => { + comp.triggerKeySequence('This is a question that needs some options.'); + const action = new MonacoCorrectMultipleChoiceAnswerAction(); + comp.registerAction(action); + action.executeInCurrentEditor(); + expect(comp.getText()).toBe('This is a question that needs some options.\n[correct] Enter a correct answer option here'); + }); + + it('should add an explanation to an answer option', () => { + comp.triggerKeySequence('This is a question that has an option.\n[correct] Option 1'); + const action = new MonacoQuizExplanationAction(); + comp.registerAction(action); + action.executeInCurrentEditor(); + expect(comp.getText()).toBe( + 'This is a question that has an option.\n[correct] Option 1\n\t[exp] Add an explanation here (only visible in feedback after quiz has ended)', + ); + }); + + it('should add a hint to an answer option', () => { + comp.triggerKeySequence('This is a question that has an option.\n[correct] Option 1'); + const action = new MonacoQuizHintAction(); + comp.registerAction(action); + action.executeInCurrentEditor(); + expect(comp.getText()).toBe('This is a question that has an option.\n[correct] Option 1\n\t[hint] Add a hint here (visible during the quiz via ?-Button)'); + }); + }); }); diff --git a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action.integration.spec.ts b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action.integration.spec.ts index c1204d455f57..3ccaa08b5f79 100644 --- a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action.integration.spec.ts +++ b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-action.integration.spec.ts @@ -180,7 +180,7 @@ describe('MonacoEditorActionIntegration', () => { const action = new MonacoTaskAction(); comp.registerAction(action); action.executeInCurrentEditor(); - expect(comp.getText()).toBe(MonacoTaskAction.INSERT_TASK_TEXT); + expect(comp.getText()).toBe(`[task]${MonacoTaskAction.TEXT}`); }); it('should enter fullscreen', () => { diff --git a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-grading-instructions.integration.spec.ts b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-grading-instructions.integration.spec.ts new file mode 100644 index 000000000000..a5df872438f0 --- /dev/null +++ b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor-grading-instructions.integration.spec.ts @@ -0,0 +1,74 @@ +import { MonacoEditorComponent } from 'app/shared/monaco-editor/monaco-editor.component'; +import { ArtemisTestModule } from '../../../test.module'; +import { MonacoEditorModule } from 'app/shared/monaco-editor/monaco-editor.module'; +import { MockResizeObserver } from '../../../helpers/mocks/service/mock-resize-observer'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MonacoGradingInstructionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-instruction.action'; +import { MonacoGradingCreditsAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-credits.action'; +import { MonacoGradingScaleAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-scale.action'; +import { MonacoGradingDescriptionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-description.action'; +import { MonacoGradingFeedbackAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-feedback.action'; +import { MonacoGradingUsageCountAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-usage-count.action'; +import { MonacoGradingCriterionAction } from 'app/shared/monaco-editor/model/actions/grading-criteria/monaco-grading-criterion.action'; + +describe('MonacoEditorActionGradingInstructionsIntegration', () => { + let fixture: ComponentFixture; + let comp: MonacoEditorComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ArtemisTestModule, MonacoEditorModule], + declarations: [MonacoEditorComponent], + providers: [], + }) + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(MonacoEditorComponent); + comp = fixture.componentInstance; + global.ResizeObserver = jest.fn().mockImplementation((callback: ResizeObserverCallback) => { + return new MockResizeObserver(callback); + }); + fixture.detectChanges(); + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + const setupActions = () => { + const creditsAction = new MonacoGradingCreditsAction(); + const scaleAction = new MonacoGradingScaleAction(); + const descriptionAction = new MonacoGradingDescriptionAction(); + const feedbackAction = new MonacoGradingFeedbackAction(); + const usageCountAction = new MonacoGradingUsageCountAction(); + const instructionAction = new MonacoGradingInstructionAction(creditsAction, scaleAction, descriptionAction, feedbackAction, usageCountAction); + const criterionAction = new MonacoGradingCriterionAction(instructionAction); + [creditsAction, scaleAction, descriptionAction, feedbackAction, usageCountAction, instructionAction, criterionAction].forEach((action) => comp.registerAction(action)); + return { creditsAction, scaleAction, descriptionAction, feedbackAction, usageCountAction, instructionAction, criterionAction }; + }; + + const expectedInstructionTextWithoutCriterion = + '\n[instruction]' + + '\n\t[credits] 0' + + '\n\t[gradingScale] Add instruction grading scale here (only visible for tutors)' + + '\n\t[description] Add grading instruction here (only visible for tutors)' + + '\n\t[feedback] Add feedback for students here (visible for students)' + + '\n\t[maxCountInScore] 0'; + + const generalInstructionText = 'These are some general instructions for the tutors.'; + + it('should insert grading instructions', () => { + comp.triggerKeySequence(generalInstructionText); + const actions = setupActions(); + actions.instructionAction.executeInCurrentEditor(); + expect(comp.getText()).toBe(generalInstructionText + expectedInstructionTextWithoutCriterion); + }); + + it('should insert grading criterion', () => { + comp.triggerKeySequence(generalInstructionText); + const actions = setupActions(); + actions.criterionAction.executeInCurrentEditor(); + expect(comp.getText()).toBe(`${generalInstructionText}\n[criterion] Add criterion title (only visible to tutors)${expectedInstructionTextWithoutCriterion}`); + }); +}); diff --git a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.component.spec.ts b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.component.spec.ts index dc9f7fb8b33c..ae34f743a3a7 100644 --- a/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.component.spec.ts +++ b/src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.component.spec.ts @@ -170,6 +170,12 @@ describe('MonacoEditorComponent', () => { expect(documentHighlightedMargins).toHaveLength(3); }); + it('should get the number of lines in the editor', () => { + fixture.detectChanges(); + comp.setText(multiLineText); + expect(comp.getNumberOfLines()).toBe(5); + }); + it('should pass the current line number to the line decorations hover button when clicked', () => { const clickCallbackStub = jest.fn(); const className = 'testClass'; diff --git a/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts b/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts index 1dcb3a517efd..da3219405bd2 100644 --- a/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts +++ b/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts @@ -5,7 +5,6 @@ import { KnowledgeAreaEditComponent } from 'app/admin/standardized-competencies/ import { ButtonComponent } from 'app/shared/components/button.component'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { TaxonomySelectComponent } from 'app/course/competencies/taxonomy-select/taxonomy-select.component'; import { TranslatePipeMock } from '../../../helpers/mocks/service/mock-translate.service'; import { TranslateDirective } from 'app/shared/language/translate.directive'; @@ -13,6 +12,7 @@ import { NgbTooltipMocksModule } from '../../../helpers/mocks/directive/ngbToolt import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.directive'; import { KnowledgeAreaDTO } from 'app/entities/competency/standardized-competency.model'; import { By } from '@angular/platform-browser'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('KnowledgeAreaEditComponent', () => { let componentFixture: ComponentFixture; @@ -44,7 +44,7 @@ describe('KnowledgeAreaEditComponent', () => { MockComponent(ButtonComponent), TranslatePipeMock, MockPipe(HtmlForMarkdownPipe), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(TaxonomySelectComponent), MockDirective(TranslateDirective), MockDirective(DeleteButtonDirective), diff --git a/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts b/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts index b33c93d1eabd..35d65359675f 100644 --- a/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts +++ b/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts @@ -6,13 +6,13 @@ import { ButtonComponent } from 'app/shared/components/button.component'; import { CompetencyTaxonomy } from 'app/entities/competency.model'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { TaxonomySelectComponent } from 'app/course/competencies/taxonomy-select/taxonomy-select.component'; import { TranslatePipeMock } from '../../../helpers/mocks/service/mock-translate.service'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { NgbTooltipMocksModule } from '../../../helpers/mocks/directive/ngbTooltipMocks.module'; import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.directive'; import { KnowledgeAreaDTO, StandardizedCompetencyDTO } from 'app/entities/competency/standardized-competency.model'; +import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; describe('StandardizedCompetencyEditComponent', () => { let componentFixture: ComponentFixture; @@ -47,7 +47,7 @@ describe('StandardizedCompetencyEditComponent', () => { MockComponent(ButtonComponent), TranslatePipeMock, MockPipe(HtmlForMarkdownPipe), - MockComponent(MarkdownEditorComponent), + MockComponent(MarkdownEditorMonacoComponent), MockComponent(TaxonomySelectComponent), MockDirective(TranslateDirective), MockDirective(DeleteButtonDirective), diff --git a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts index 04d2c353f042..06e2de934c41 100644 --- a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts +++ b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts @@ -26,7 +26,7 @@ import { generateClickSubmitButton, generateTestFormIsInvalidOnMissingRequiredPr import { ArtemisDateRangePipe } from 'app/shared/pipes/artemis-date-range.pipe'; import { runOnPushChangeDetection } from '../../../../../helpers/on-push-change-detection.helper'; -@Component({ selector: 'jhi-markdown-editor', template: '' }) +@Component({ selector: 'jhi-markdown-editor-monaco', template: '' }) class MarkdownEditorStubComponent { @Input() markdown: string; @Input() enableResize = false; diff --git a/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts b/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts index 5fffcf112b9e..a793a859f204 100644 --- a/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts +++ b/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts @@ -56,7 +56,6 @@ import { CodeEditorBuildOutputComponent } from 'app/exercises/programming/shared import { KeysPipe } from 'app/shared/pipes/keys.pipe'; import { CodeEditorInstructionsComponent } from 'app/exercises/programming/shared/code-editor/instructions/code-editor-instructions.component'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; -import { MarkdownEditorComponent } from 'app/shared/markdown-editor/markdown-editor.component'; import { ProgrammingExerciseInstructionComponent } from 'app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component'; import { ProgrammingExerciseInstructionAnalysisComponent } from 'app/exercises/programming/manage/instructions-editor/analysis/programming-exercise-instruction-analysis.component'; import { ResultComponent } from 'app/exercises/shared/result/result.component'; @@ -107,7 +106,6 @@ describe('CodeEditorInstructorIntegration', () => { UpdatingResultComponent, MockComponent(ProgrammingExerciseStudentTriggerBuildButtonComponent), ProgrammingExerciseEditableInstructionComponent, - MockComponent(MarkdownEditorComponent), MockComponent(MarkdownEditorMonacoComponent), ProgrammingExerciseInstructionComponent, MockComponent(ProgrammingExerciseInstructionAnalysisComponent), diff --git a/src/test/playwright/support/pageobjects/course/CourseCommunicationPage.ts b/src/test/playwright/support/pageobjects/course/CourseCommunicationPage.ts index 17d24b98c07a..6fd47e0a9a7f 100644 --- a/src/test/playwright/support/pageobjects/course/CourseCommunicationPage.ts +++ b/src/test/playwright/support/pageobjects/course/CourseCommunicationPage.ts @@ -156,7 +156,7 @@ export class CourseCommunicationPage { */ async reply(postID: number, content: string) { const postElement = this.getSinglePost(postID); - const postReplyField = postElement.locator('.new-reply-inline-input .markdown-editor .ace_content'); + const postReplyField = postElement.locator('.new-reply-inline-input .markdown-editor .monaco-editor'); await postReplyField.click(); await postReplyField.pressSequentially(content); const responsePromise = this.page.waitForResponse(`${COURSE_BASE}/*/answer-posts`); @@ -172,7 +172,7 @@ export class CourseCommunicationPage { */ async replyWithMessage(postID: number, content: string): Promise { const postElement = this.getSinglePost(postID); - const postReplyField = postElement.locator('.new-reply-inline-input .markdown-editor .ace_content'); + const postReplyField = postElement.locator('.new-reply-inline-input .markdown-editor .monaco-editor'); await postReplyField.click(); await postReplyField.pressSequentially(content); const responsePromise = this.page.waitForResponse(`${COURSE_BASE}/*/answer-messages`); diff --git a/src/test/playwright/support/pageobjects/exam/ExamCreationPage.ts b/src/test/playwright/support/pageobjects/exam/ExamCreationPage.ts index 53ac528bcdcc..e710822e6723 100644 --- a/src/test/playwright/support/pageobjects/exam/ExamCreationPage.ts +++ b/src/test/playwright/support/pageobjects/exam/ExamCreationPage.ts @@ -131,15 +131,10 @@ export class ExamCreationPage { private async enterText(selector: string, text: string) { const textField = this.page.locator(selector); - const textInput = textField.locator('.ace_text-input'); - // const currentText = textField.locator('.ace_text'); - - // if (await currentText.isVisible()) { - // const text = await currentText.textContent(); + const textInput = textField.locator('.monaco-editor'); if (text) { await clearTextField(textInput); } - // } await textInput.pressSequentially(text); } } diff --git a/src/test/playwright/support/pageobjects/exam/ExamManagementPage.ts b/src/test/playwright/support/pageobjects/exam/ExamManagementPage.ts index ad7dae5a7225..e2e5f76c24f0 100644 --- a/src/test/playwright/support/pageobjects/exam/ExamManagementPage.ts +++ b/src/test/playwright/support/pageobjects/exam/ExamManagementPage.ts @@ -114,7 +114,7 @@ export class ExamManagementPage { } async typeAnnouncementMessage(message: string) { - await this.page.locator('.ace_text-input').fill(message); + await this.page.locator('.monaco-editor textarea').fill(message); } async verifyAnnouncementContent(announcementTime: Dayjs, message: string, authorUsername: string) { diff --git a/src/test/playwright/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts b/src/test/playwright/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts index 1520841bccf9..760eb91275dc 100644 --- a/src/test/playwright/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts +++ b/src/test/playwright/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts @@ -53,6 +53,6 @@ export class FileUploadExerciseCreationPage { } private async typeText(selector: string, text: string) { - await this.page.locator(selector).locator('.ace_content').pressSequentially(text); + await this.page.locator(selector).locator('.monaco-editor').pressSequentially(text); } } diff --git a/src/test/playwright/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts b/src/test/playwright/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts index 7317e96d0711..9cccd6576272 100644 --- a/src/test/playwright/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts +++ b/src/test/playwright/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts @@ -25,8 +25,8 @@ export class QuizExerciseCreationPage { await this.page.locator('#score').fill(points.toString()); const fileContent = await Fixtures.get('exercise/quiz/multiple_choice/question.txt'); - const textInputField = this.page.locator('.ace_text-input'); - await textInputField.focus(); + const textInputField = this.page.locator('.monaco-editor'); + await textInputField.click(); await textInputField.pressSequentially(fileContent!); } @@ -61,9 +61,9 @@ export class QuizExerciseCreationPage { await drag(this.page, dragLocator, dropLocator); const fileContent = await Fixtures.get('exercise/quiz/drag_and_drop/question.txt'); - const textInputField = this.page.locator('.ace_text-input'); + const textInputField = this.page.locator('.monaco-editor'); await clearTextField(textInputField); - await textInputField.fill(fileContent!); + await textInputField.pressSequentially(fileContent!); } async createDragAndDropItem(text: string) { diff --git a/src/test/playwright/support/pageobjects/exercises/text/TextExerciseCreationPage.ts b/src/test/playwright/support/pageobjects/exercises/text/TextExerciseCreationPage.ts index a18217aac3d1..7d13e7ee1101 100644 --- a/src/test/playwright/support/pageobjects/exercises/text/TextExerciseCreationPage.ts +++ b/src/test/playwright/support/pageobjects/exercises/text/TextExerciseCreationPage.ts @@ -57,7 +57,7 @@ export class TextExerciseCreationPage { } private async typeText(selector: string, text: string) { - const textField = this.page.locator(selector).locator('.ace_content'); + const textField = this.page.locator(selector).locator('.monaco-editor'); await textField.click(); await textField.pressSequentially(text); } diff --git a/src/test/playwright/support/pageobjects/lecture/LectureCreationPage.ts b/src/test/playwright/support/pageobjects/lecture/LectureCreationPage.ts index 2d2e122969a6..8e4fa68e7f31 100644 --- a/src/test/playwright/support/pageobjects/lecture/LectureCreationPage.ts +++ b/src/test/playwright/support/pageobjects/lecture/LectureCreationPage.ts @@ -35,7 +35,7 @@ export class LectureCreationPage { * @param description - The description text for the lecture. */ async typeDescription(description: string) { - const descriptionField = this.page.locator('.ace_content'); + const descriptionField = this.page.locator('.monaco-editor'); await descriptionField.click(); await descriptionField.pressSequentially(description); } diff --git a/src/test/playwright/support/pageobjects/lecture/LectureManagementPage.ts b/src/test/playwright/support/pageobjects/lecture/LectureManagementPage.ts index af5624689a7d..40b336fdb1de 100644 --- a/src/test/playwright/support/pageobjects/lecture/LectureManagementPage.ts +++ b/src/test/playwright/support/pageobjects/lecture/LectureManagementPage.ts @@ -95,7 +95,7 @@ export class LectureManagementPage { await this.openCreateUnit(UnitType.TEXT); await this.page.fill('#name', name); await this.page.fill('#pick-releaseDate #date-input-field', releaseDate.toString()); - const contentField = this.page.locator('.ace_content'); + const contentField = this.page.locator('.monaco-editor'); await contentField.click(); await contentField.pressSequentially(text); return this.submitUnit(); From 1bb98807618a5f6c4d4a859a96273db296414b67 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sat, 24 Aug 2024 18:39:06 +0300 Subject: [PATCH 15/60] Development: Update client dependencies --- package-lock.json | 534 +++++++++++++++++++++++++--------------------- package.json | 52 +++-- 2 files changed, 321 insertions(+), 265 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc5fa5d014c4..4ac4c8f4a4b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,18 +10,18 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@angular/animations": "18.2.0", - "@angular/cdk": "18.2.0", - "@angular/common": "18.2.0", - "@angular/compiler": "18.2.0", - "@angular/core": "18.2.0", - "@angular/forms": "18.2.0", - "@angular/localize": "18.2.0", - "@angular/material": "18.2.0", - "@angular/platform-browser": "18.2.0", - "@angular/platform-browser-dynamic": "18.2.0", - "@angular/router": "18.2.0", - "@angular/service-worker": "18.2.0", + "@angular/animations": "18.2.1", + "@angular/cdk": "18.2.1", + "@angular/common": "18.2.1", + "@angular/compiler": "18.2.1", + "@angular/core": "18.2.1", + "@angular/forms": "18.2.1", + "@angular/localize": "18.2.1", + "@angular/material": "18.2.1", + "@angular/platform-browser": "18.2.1", + "@angular/platform-browser-dynamic": "18.2.1", + "@angular/router": "18.2.1", + "@angular/service-worker": "18.2.1", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.1.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -38,7 +38,7 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.5", + "ace-builds": "1.36.0", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", @@ -57,7 +57,7 @@ "jszip": "3.10.1", "lodash-es": "4.17.21", "mobile-drag-drop": "3.0.0-rc.0", - "monaco-editor": "0.50.0", + "monaco-editor": "0.51.0", "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", @@ -66,12 +66,12 @@ "showdown": "2.1.0", "showdown-highlight": "3.1.0", "showdown-katex": "0.6.0", - "simple-statistics": "7.8.3", + "simple-statistics": "7.8.4", "smoothscroll-polyfill": "0.4.4", "sockjs-client": "1.6.1", "split.js": "1.6.5", "ts-cacheable": "1.0.10", - "tslib": "2.6.3", + "tslib": "2.7.0", "uuid": "10.0.0", "webstomp-client": "1.2.6", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", @@ -79,22 +79,22 @@ }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.2.0", + "@angular-devkit/build-angular": "18.2.1", "@angular-eslint/builder": "18.3.0", "@angular-eslint/eslint-plugin": "18.3.0", "@angular-eslint/eslint-plugin-template": "18.3.0", "@angular-eslint/schematics": "18.3.0", "@angular-eslint/template-parser": "18.3.0", - "@angular/cli": "18.2.0", - "@angular/compiler-cli": "18.2.0", - "@angular/language-service": "18.2.0", + "@angular/cli": "18.2.1", + "@angular/compiler-cli": "18.2.1", + "@angular/language-service": "18.2.1", "@sentry/types": "8.26.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.4.2", + "@types/node": "22.5.0", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", @@ -102,7 +102,7 @@ "@types/uuid": "10.0.0", "@typescript-eslint/eslint-plugin": "8.2.0", "@typescript-eslint/parser": "8.2.0", - "eslint": "9.9.0", + "eslint": "9.9.1", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", "eslint-plugin-jest": "28.8.0", @@ -121,7 +121,7 @@ "ng-mocks": "14.13.0", "prettier": "3.3.3", "sass": "1.77.8", - "ts-jest": "29.2.4", + "ts-jest": "29.2.5", "typescript": "5.5.4", "weak-napi": "2.0.2" }, @@ -211,13 +211,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.0.tgz", - "integrity": "sha512-s1atTSL98XLUUxfWEQAnhFaOFIJZDLWjSqec+Sb+f4iZFj+hOFejzJxPVnHMIJudOzn0Lqjk3t987KG/zNEGdg==", + "version": "0.1802.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.1.tgz", + "integrity": "sha512-XTnJfCBMDQl3xF4w/eNrq821gbj2Ig1cqbzpRflhz4pqrANTAfHfPoIC7piWEZ60FNlHapzb6fvh6tJUGXG9og==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.0", + "@angular-devkit/core": "18.2.1", "rxjs": "7.8.1" }, "engines": { @@ -227,17 +227,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.0.tgz", - "integrity": "sha512-V0XKT7xt6d6duXqmDAQEQgEJNXuWAekpHEDxafvBT0MTxcEhu0ozQVwI4oAekiKOz+APIcAZyMzvw3Tlzog5cw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.1.tgz", + "integrity": "sha512-ANsTWKjIlEvJ6s276TbwnDhkoHhQDfsNiRFUDRGBZu94UNR78ImQZSyKYGHJOeQQH6jpBtraA1rvW5WKozAtlw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.0", - "@angular-devkit/build-webpack": "0.1802.0", - "@angular-devkit/core": "18.2.0", - "@angular/build": "18.2.0", + "@angular-devkit/architect": "0.1802.1", + "@angular-devkit/build-webpack": "0.1802.1", + "@angular-devkit/core": "18.2.1", + "@angular/build": "18.2.1", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -248,7 +248,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.0", + "@ngtools/webpack": "18.2.1", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -280,7 +280,7 @@ "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.77.8", + "sass": "1.77.6", "sass-loader": "16.0.0", "semver": "7.6.3", "source-map-loader": "5.0.0", @@ -355,14 +355,39 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/sass": { + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.0.tgz", - "integrity": "sha512-bU7AxlI/avnlOLrgE195cokrOA1ayT6JjRv8Hxzh1bIOa1jE87HsyjxvQhOLcdEb97zwHqMqbntcgUNBgsegJQ==", + "version": "0.1802.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.1.tgz", + "integrity": "sha512-xOP9Hxkj/mWYdMTa/8uNxFTv7z+3UiGdt4VAO7vetV5qkU/S9rRq8FEKviCc2llXfwkhInSgeeHpWKdATa+YIQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.0", + "@angular-devkit/architect": "0.1802.1", "rxjs": "7.8.1" }, "engines": { @@ -376,9 +401,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.0.tgz", - "integrity": "sha512-8SOopyUKUMqAq2rj32XkTIfr79Y274k4uglxxRtzHYoWwHlLdG0KrA+wCcsh/FU9PyR4dA+5dcDAApn358ZF+Q==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.1.tgz", + "integrity": "sha512-fSuGj6CxiTFR+yjuVcaWqaVb5Wts39CSBYRO1BlsOlbuWFZ2NKC/BAb5bdxpB31heCBJi7e3XbPvcMMJIcnKlA==", "dev": true, "license": "MIT", "dependencies": { @@ -404,13 +429,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.0.tgz", - "integrity": "sha512-WWKwz2RKMVI6T25JFwOSSfRLB+anNzabVIRwf85R/YMIo34BUk777f2JU/7cCKlxSpQu39TqIfMQZAyzAD1z0A==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.1.tgz", + "integrity": "sha512-2t/q0Jcv7yqhAzEdNgsxoGSCmPgD4qfnVOJ7EJw3LNIA+kX1CmtN4FESUS0i49kN4AyNJFAI5O2pV8iJiliKaw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.0", + "@angular-devkit/core": "18.2.1", "jsonc-parser": "3.3.1", "magic-string": "0.30.11", "ora": "5.4.1", @@ -523,9 +548,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.0.tgz", - "integrity": "sha512-BFAfqDDjsa0Q91F4s33pFcBG+ydFDurEmwYGG1gmO7UXZJI6ZbRVdULaZHz75M+Bf3hJkzVB05pesvfbK+Fg/g==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.1.tgz", + "integrity": "sha512-jit452yuE6DMVV09E6RAjgapgw64mMVH31ccpPvMDekzPsTuP3KNKtgRFU/k2DFhYJvyczM1AqqlgccE/JGaRw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -534,18 +559,18 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.0" + "@angular/core": "18.2.1" } }, "node_modules/@angular/build": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.0.tgz", - "integrity": "sha512-LvNJ2VOEVy3N1tGzt+xnKyweRBuUE1NsnuEEWAb9Y+V1cyRgj0s7FX2+IQZZQhP+W/pXfbsKaByOAbJ5KWV85Q==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.1.tgz", + "integrity": "sha512-HwzjB+I31cAtjTTbbS2NbayzfcWthaKaofJlSmZIst3PN+GwLZ8DU0DRpd/xu5AXkk+DoAIWd+lzUIaqngz6ow==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.0", + "@angular-devkit/architect": "0.1802.1", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -565,7 +590,7 @@ "picomatch": "4.0.2", "piscina": "4.6.1", "rollup": "4.20.0", - "sass": "1.77.8", + "sass": "1.77.6", "semver": "7.6.3", "vite": "5.4.0", "watchpack": "2.4.1" @@ -606,10 +631,28 @@ } } }, + "node_modules/@angular/build/node_modules/sass": { + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@angular/cdk": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.0.tgz", - "integrity": "sha512-hjuUWNhxU48WB2i1j4NLwnPTaCnucRElfp7DBX5Io0rY5Lwl3HXafvyi7/A1D0Ah+YsJpktKOWPDGv8r7vxymg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.1.tgz", + "integrity": "sha512-6y4MmpEPXze6igUHkLsBUPkxw32F8+rmW0xVXZchkSyGlFgqfh53ueXoryWb0qL4s5enkNY6AzXnKAqHfPNkVQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -624,18 +667,18 @@ } }, "node_modules/@angular/cli": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.0.tgz", - "integrity": "sha512-hA60QIA7Dh8LQxM42wqd7WrhwQjbjB8oIRH5Slgbiv8iocAo76scp1/qyZo2SSzjfkB7jxUiao5L4ckiJ/hvZg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.1.tgz", + "integrity": "sha512-SomUFDHanY4o7k3XBGf1eFt4z1h05IGJHfcbl2vxoc0lY59VN13m/pZsD2AtpqtJTzLQT02XQOUP4rmBbGoQ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.0", - "@angular-devkit/core": "18.2.0", - "@angular-devkit/schematics": "18.2.0", + "@angular-devkit/architect": "0.1802.1", + "@angular-devkit/core": "18.2.1", + "@angular-devkit/schematics": "18.2.1", "@inquirer/prompts": "5.3.8", "@listr2/prompt-adapter-inquirer": "2.0.15", - "@schematics/angular": "18.2.0", + "@schematics/angular": "18.2.1", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", @@ -658,9 +701,9 @@ } }, "node_modules/@angular/common": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.0.tgz", - "integrity": "sha512-DELx/QYNqqjmiM+kE5PoVmyG4gPw5WB1bDDeg3hEuBCK3eS2KosgQH0/MQo3OSBZHOcAMFjfHMGqKgxndmYixQ==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.1.tgz", + "integrity": "sha512-N0ZJO1/iU9UhprplZRPvBcdRgA/i6l6Ng5gXs5ymHBJ0lxsB+mDVCmC4jISjR9gAWc426xXwLaOpuP5Gv3f/yg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -669,14 +712,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.0", + "@angular/core": "18.2.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.0.tgz", - "integrity": "sha512-RmGwQ7jRzotUKKMk0CwxTcIXFr5mRxSbJf9o5S3ujuIOo1lYop8SQZvjq67a5BuoYyD+1pX6iMmxZqlbKoihBQ==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.1.tgz", + "integrity": "sha512-5e9ygKEcsBoV6xpaGKVrtsLxLETlrM0oB7twl4qG/xuKYqCLj8cRQMcAKSqDfTPzWMOAQc7pHdk+uFVo/8dWHA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -685,7 +728,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.2.0" + "@angular/core": "18.2.1" }, "peerDependenciesMeta": { "@angular/core": { @@ -694,9 +737,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.0.tgz", - "integrity": "sha512-pPBFjMqNTNettrleLtEc6a/ysOZjG3F0Z5lyKYePcyNQmn2rpa9XmD2y6PhmzTmIhxeXrogWA84Xgg/vK5wBNw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.1.tgz", + "integrity": "sha512-D+Qba0r6RfHfffzrebGYp54h05AxpkagLjit/GczKNgWSP1gIgZxSfi88D+GvFmeWvZxWN1ecAQ+yqft9hJqWg==", "license": "MIT", "dependencies": { "@babel/core": "7.25.2", @@ -717,14 +760,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.2.0", + "@angular/compiler": "18.2.1", "typescript": ">=5.4 <5.6" } }, "node_modules/@angular/core": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.0.tgz", - "integrity": "sha512-7+4wXfeAk1TnG3MGho2gpBI5XHxeSRWzLK2rC5qyyRbmMV+GrIgf1HqFjQ4S02rydkQvGpjqQHtO1PYJnyn4bg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.1.tgz", + "integrity": "sha512-9KrSpJ65UlJZNXrE18NszcfOwb5LZgG+LYi5Doe7amt218R1bzb3trvuAm0ZzMaoKh4ugtUCkzEOd4FALPEX6w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -738,9 +781,9 @@ } }, "node_modules/@angular/forms": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.0.tgz", - "integrity": "sha512-G+4BjNCUo4cRwg9NwisGLbtG/1AbIJNOO3RUejPJJbCcAkYMSzmDWSQ+LQEGW4vC/1xaDKO8AT71DI/I09bOxA==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.1.tgz", + "integrity": "sha512-T7z8KUuj2PoPxrMrAruQVJha+x4a9Y6IrKYtArgOQQlTwCEJuqpVYuOk5l3fwWpHE9bVEjvgkAMI1D5YXA/U6w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -749,16 +792,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.0", - "@angular/core": "18.2.0", - "@angular/platform-browser": "18.2.0", + "@angular/common": "18.2.1", + "@angular/core": "18.2.1", + "@angular/platform-browser": "18.2.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.0.tgz", - "integrity": "sha512-brl5061YqfNnT7yZNMWmsgv6ve6p9+kfhX6mZWOGICcY2SYVtCNVHdqzwWTTwY7MvTVfycHxiAf9PEmc5lD4/g==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.1.tgz", + "integrity": "sha512-JI4oox9ELNdDVg0uJqCwgyFoK4XrowV14wSoNpGhpTLModRg3eDS6q+8cKn27cjTQRZvpReyYSTfiZMB8j4eqQ==", "dev": true, "license": "MIT", "engines": { @@ -766,9 +809,9 @@ } }, "node_modules/@angular/localize": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.2.0.tgz", - "integrity": "sha512-ul8yGmimiHkhUU87isDCst0790jTBHP1zPBMI2q7QHv7iDzSN5brV8zUMcRypxhh4mQOCnq2LtP84o5ybn4Sig==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.2.1.tgz", + "integrity": "sha512-nNdB6ehXCSBpQ75sTh6Gcwy2rgExfZEkGcPARJLpjqQlHO+Mk3b1y3ka6XT9M2qQYUeyukncTFUMEZWwHICsOA==", "license": "MIT", "dependencies": { "@babel/core": "7.25.2", @@ -785,21 +828,21 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.2.0", - "@angular/compiler-cli": "18.2.0" + "@angular/compiler": "18.2.1", + "@angular/compiler-cli": "18.2.1" } }, "node_modules/@angular/material": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.0.tgz", - "integrity": "sha512-lOXk8pAVP4Mr0/Q6YrNnVYQVTnR8aEG5D9QSEWjs+607gONuh/9n7ERBdzX7xO9D0vYyXq+Vil32zcF41/Q8Cg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.1.tgz", + "integrity": "sha512-DBSJGqLttT9vYpLGWTuuRoOKd1mNelS0jnNo7jNZyMpjcGfuhNzmPtYiBkXfNsAl7YoXoUmX8+4uh1JZspQGqA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.2.0", + "@angular/cdk": "18.2.1", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -808,9 +851,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.0.tgz", - "integrity": "sha512-yhj281TuPz5a8CehwucwIVl29Oqte9KS4X/VQkMV++GpYQE2KKKcoff4FXSdF5RUcUYkK2li4IvawIqPmUSagg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.1.tgz", + "integrity": "sha512-hQABX7QotGmCIR3EhCBCDh5ZTvQao+JkuK5CCw2G1PkRfJMBwEpjNqnyhz41hZhWiGlucp9jgbeypppW+mIQEw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -819,9 +862,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.2.0", - "@angular/common": "18.2.0", - "@angular/core": "18.2.0" + "@angular/animations": "18.2.1", + "@angular/common": "18.2.1", + "@angular/core": "18.2.1" }, "peerDependenciesMeta": { "@angular/animations": { @@ -830,9 +873,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.0.tgz", - "integrity": "sha512-izfaXKNC/kqOEzJG8eTnFu39VLI3vv3dTKoYOdEKRB7MTI0t0x66oZmABnHcihtkTSvXs/is+7lA5HmH2ZuIEQ==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.1.tgz", + "integrity": "sha512-tYJHtshbaKrtnRA15k3vrveSVBqkVUGhINvGugFA2vMtdTOfhfPw+hhzYrcwJibgU49rHogCfI9mkIbpNRYntA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -841,16 +884,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.0", - "@angular/compiler": "18.2.0", - "@angular/core": "18.2.0", - "@angular/platform-browser": "18.2.0" + "@angular/common": "18.2.1", + "@angular/compiler": "18.2.1", + "@angular/core": "18.2.1", + "@angular/platform-browser": "18.2.1" } }, "node_modules/@angular/router": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.0.tgz", - "integrity": "sha512-6/462hvC3HSwbps8VItECHpkdkiFqRmTKdn1Trik+FjnvdupYrKB6kBsveM3eP+gZD4zyMBMKzBWB9N/xA1clw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.1.tgz", + "integrity": "sha512-gVyqW6fYnG7oq1DlZSXJMQ2Py2dJQB7g6XVtRcYB1gR4aeowx5N9ws7PjqAi0ih91ASq2MmP4OlSSWLq+eaMGg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -859,16 +902,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.0", - "@angular/core": "18.2.0", - "@angular/platform-browser": "18.2.0", + "@angular/common": "18.2.1", + "@angular/core": "18.2.1", + "@angular/platform-browser": "18.2.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.0.tgz", - "integrity": "sha512-ngcALrgqMuAeIo5dgou6eBzdtgLvmVg5zwmZuTyrnNPZENEaKTj7u5pm9++gl62797sUWlMbL+fa/BOhntGs5A==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.1.tgz", + "integrity": "sha512-Is4arGy+4HjyvALmR/GsWI4SwXYVJ1IkauAgxPsQKvWLNHdX7a/CEgEEVQGXq96H46QX9O2OcW69PnPatmJIXg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -880,8 +923,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.2.0", - "@angular/core": "18.2.0" + "@angular/common": "18.2.1", + "@angular/core": "18.2.1" } }, "node_modules/@babel/code-frame": { @@ -898,9 +941,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1000,9 +1043,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", - "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1011,7 +1054,7 @@ "@babel/helper-optimise-call-expression": "^7.24.7", "@babel/helper-replace-supers": "^7.25.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/traverse": "^7.25.0", + "@babel/traverse": "^7.25.4", "semver": "^6.3.1" }, "engines": { @@ -1270,12 +1313,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.2" + "@babel/types": "^7.25.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -1646,13 +1689,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1764,14 +1807,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1799,17 +1842,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", - "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-replace-supers": "^7.25.0", - "@babel/traverse": "^7.25.0", + "@babel/traverse": "^7.25.4", "globals": "^11.1.0" }, "engines": { @@ -2280,14 +2323,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2517,14 +2560,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2680,16 +2723,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", "@babel/template": "^7.25.0", - "@babel/types": "^7.25.2", + "@babel/types": "^7.25.4", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2697,10 +2740,25 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.4", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -3240,9 +3298,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3364,9 +3422,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", - "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "dev": true, "license": "MIT", "engines": { @@ -5006,9 +5064,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.0.tgz", - "integrity": "sha512-a6hbkYzh/KUlI52huiU4vztqIuxzyddg6kJGcelUJx3Ju6MJeziu+XmJ6wqFRvfH89zmJeaSADKsGFQaBHtJLg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.1.tgz", + "integrity": "sha512-v86U3jOoy5R9ZWe9Q0LbHRx/IBw1lbn0ldBU+gIIepREyVvb9CcH/vAyIb2Fw1zaYvvfG1OyzdrHyW8iGXjdnQ==", "dev": true, "license": "MIT", "engines": { @@ -5653,14 +5711,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.0.tgz", - "integrity": "sha512-XePvx2ZnxCcAQw5lHVMUrJvm8MXqAWGcMyJDAuQUqNZrPCk3GpCaplWx2n+nPkinYVX2Q2v/DqtvWStQwgU4nA==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.1.tgz", + "integrity": "sha512-bBV7I+MCbdQmBPUFF4ECg37VReM0+AdQsxgwkjBBSYExmkErkDoDgKquwL/tH7stDCc5IfTd0g9BMeosRgDMug==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.0", - "@angular-devkit/schematics": "18.2.0", + "@angular-devkit/core": "18.2.1", + "@angular-devkit/schematics": "18.2.1", "jsonc-parser": "3.3.1" }, "engines": { @@ -6398,9 +6456,9 @@ } }, "node_modules/@types/node": { - "version": "22.4.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", - "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", + "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", "dev": true, "license": "MIT", "dependencies": { @@ -6448,9 +6506,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", + "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -7019,9 +7077,9 @@ } }, "node_modules/ace-builds": { - "version": "1.35.5", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.5.tgz", - "integrity": "sha512-yh3V5BLHlN6gwbmk5sV00WRRvdEggJGJ3AIHhOOGHlgDWNWCSvOnHPO7Chb+AqaxxHuvpxOdXd7ZQesaiuJQZQ==", + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.36.0.tgz", + "integrity": "sha512-7to4F86V5N13EY4M9LWaGo2Wmr9iWe5CrYpc28F+/OyYCf7yd+xBV5x9v/GB73EBGGoYd89m6JjeIUjkL6Yw+w==", "license": "BSD-3-Clause" }, "node_modules/acorn": { @@ -7301,9 +7359,9 @@ } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true, "license": "MIT" }, @@ -8654,9 +8712,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.38.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz", - "integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, "license": "MIT", "dependencies": { @@ -9714,9 +9772,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.8.tgz", - "integrity": "sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "license": "ISC" }, "node_modules/emittery": { @@ -9974,17 +10032,17 @@ } }, "node_modules/eslint": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", - "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.1", + "@eslint/config-array": "^0.18.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.9.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -12115,9 +12173,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -15567,9 +15625,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -15898,9 +15956,9 @@ "license": "MIT" }, "node_modules/monaco-editor": { - "version": "0.50.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz", - "integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==", + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.51.0.tgz", + "integrity": "sha512-xaGwVV1fq343cM7aOYB6lVE4Ugf0UyimdD/x5PWcWBMKENwectaEu77FAN7c5sFiyumqeJdX1RPTh1ocioyDjw==", "license": "MIT" }, "node_modules/moo-color": { @@ -17212,9 +17270,9 @@ } }, "node_modules/postcss": { - "version": "8.4.40", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", - "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, "funding": [ { @@ -18764,12 +18822,12 @@ } }, "node_modules/simple-statistics": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-7.8.3.tgz", - "integrity": "sha512-JFvMY00t6SBGtwMuJ+nqgsx9ylkMiJ5JlK9bkj8AdvniIe5615wWQYkKHXe84XtSuc40G/tlrPu0A5/NlJvv8A==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-7.8.4.tgz", + "integrity": "sha512-KHC7X+4Dji2rFgnPU7FxPPp4GxPz9hvQCHx2x6JbjLYNKuSMHcoNZ54gF0xBBMOAvNtWmfCHcfC4MD2T89ffEA==", "license": "ISC", "engines": { - "node": "*" + "node": ">= 18" } }, "node_modules/sisteransi": { @@ -19012,9 +19070,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", "dev": true, "license": "CC0-1.0" }, @@ -19833,21 +19891,21 @@ } }, "node_modules/ts-jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", - "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", "dev": true, "license": "MIT", "dependencies": { - "bs-logger": "0.x", + "bs-logger": "^0.2.6", "ejs": "^3.1.10", - "fast-json-stable-stringify": "2.x", + "fast-json-stable-stringify": "^2.1.0", "jest-util": "^29.0.0", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" }, "bin": { "ts-jest": "cli.js" @@ -19951,9 +20009,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "license": "0BSD" }, "node_modules/tsutils": { @@ -21022,9 +21080,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", - "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1eda30265f5f..da3d4a60a893 100644 --- a/package.json +++ b/package.json @@ -13,18 +13,18 @@ "node_modules" ], "dependencies": { - "@angular/animations": "18.2.0", - "@angular/cdk": "18.2.0", - "@angular/common": "18.2.0", - "@angular/compiler": "18.2.0", - "@angular/core": "18.2.0", - "@angular/forms": "18.2.0", - "@angular/localize": "18.2.0", - "@angular/material": "18.2.0", - "@angular/platform-browser": "18.2.0", - "@angular/platform-browser-dynamic": "18.2.0", - "@angular/router": "18.2.0", - "@angular/service-worker": "18.2.0", + "@angular/animations": "18.2.1", + "@angular/cdk": "18.2.1", + "@angular/common": "18.2.1", + "@angular/compiler": "18.2.1", + "@angular/core": "18.2.1", + "@angular/forms": "18.2.1", + "@angular/localize": "18.2.1", + "@angular/material": "18.2.1", + "@angular/platform-browser": "18.2.1", + "@angular/platform-browser-dynamic": "18.2.1", + "@angular/router": "18.2.1", + "@angular/service-worker": "18.2.1", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.1.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -41,7 +41,7 @@ "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", - "ace-builds": "1.35.5", + "ace-builds": "1.36.0", "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", @@ -60,7 +60,7 @@ "jszip": "3.10.1", "lodash-es": "4.17.21", "mobile-drag-drop": "3.0.0-rc.0", - "monaco-editor": "0.50.0", + "monaco-editor": "0.51.0", "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", @@ -69,12 +69,12 @@ "showdown": "2.1.0", "showdown-highlight": "3.1.0", "showdown-katex": "0.6.0", - "simple-statistics": "7.8.3", + "simple-statistics": "7.8.4", "smoothscroll-polyfill": "0.4.4", "sockjs-client": "1.6.1", "split.js": "1.6.5", "ts-cacheable": "1.0.10", - "tslib": "2.6.3", + "tslib": "2.7.0", "uuid": "10.0.0", "webstomp-client": "1.2.6", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", @@ -91,7 +91,6 @@ "@typescript-eslint/utils": { "eslint": "^9.9.0" }, - "axios": "1.7.4", "braces": "3.0.3", "critters": "0.0.24", "debug": "4.3.6", @@ -103,36 +102,35 @@ }, "jsdom": "24.1.1", "katex": "0.16.11", - "postcss": "8.4.40", + "postcss": "8.4.41", "semver": "7.6.3", "showdown-katex": { "showdown": "2.1.0" }, "tough-cookie": "4.1.4", - "undici": "6.19.5", - "webpack-dev-middleware": "7.3.0", + "webpack-dev-middleware": "7.4.2", "word-wrap": "1.2.5", "ws": "8.18.0", "yargs-parser": "21.1.1" }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.2.0", + "@angular-devkit/build-angular": "18.2.1", "@angular-eslint/builder": "18.3.0", "@angular-eslint/eslint-plugin": "18.3.0", "@angular-eslint/eslint-plugin-template": "18.3.0", "@angular-eslint/schematics": "18.3.0", "@angular-eslint/template-parser": "18.3.0", - "@angular/cli": "18.2.0", - "@angular/compiler-cli": "18.2.0", - "@angular/language-service": "18.2.0", + "@angular/cli": "18.2.1", + "@angular/compiler-cli": "18.2.1", + "@angular/language-service": "18.2.1", "@sentry/types": "8.26.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", "@types/jest": "29.5.12", "@types/lodash-es": "4.17.12", - "@types/node": "22.4.2", + "@types/node": "22.5.0", "@types/papaparse": "5.3.14", "@types/showdown": "2.0.6", "@types/smoothscroll-polyfill": "0.3.4", @@ -140,7 +138,7 @@ "@types/uuid": "10.0.0", "@typescript-eslint/eslint-plugin": "8.2.0", "@typescript-eslint/parser": "8.2.0", - "eslint": "9.9.0", + "eslint": "9.9.1", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", "eslint-plugin-jest": "28.8.0", @@ -159,7 +157,7 @@ "ng-mocks": "14.13.0", "prettier": "3.3.3", "sass": "1.77.8", - "ts-jest": "29.2.4", + "ts-jest": "29.2.5", "typescript": "5.5.4", "weak-napi": "2.0.2" }, From 19c6b58041365a39dcd8be5ed8175d3b211d3379 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sun, 25 Aug 2024 22:57:47 +0300 Subject: [PATCH 16/60] Development: Improve contributing guidelines --- CONTRIBUTING.md | 41 +++++++++++++++++++- README.md | 99 ++++++++++++++++++++++++++----------------------- 2 files changed, 92 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea3d5c107479..482bdb00df6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,43 @@ -# Contributing Guide for Artemis +# Contribution Guidelines for Artemis Read the [setup guide](https://docs.artemis.cit.tum.de/dev/setup.html) on how to set up your local development environment. -Before creating a pull request, please read the [guidelines to the development process](https://docs.artemis.cit.tum.de/dev/development-process/development-process.html) as well as the [coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines.html). +## Identity and Transparency + +To ensure a transparent and trustworthy environment, we have established different guidelines for members of our organization and external contributors. + +### For Members of Our Organization + +1. **Real Names Required**: As a member of our organization, you must use your full real name in your GitHub profile. This is a prerequisite for joining our organization. Using a real name is crucial for building trust within the team and the broader community. It fosters accountability and transparency, which are essential for collaborative work. When members use their real identities, it encourages open communication and strengthens professional relationships. Furthermore, it aligns with best practices in open-source communities, where transparency is key to ensuring the integrity and reliability of contributions. + +2. **Profile Picture**: Members are required to upload an authentic profile picture. Use a clear, professional image and avoid comic-like pictures, memojis, or other non-authentic picture styles. Using a professional and authentic profile picture is essential for establishing credibility and fostering trust within the community. It helps others easily identify and connect with you, which is crucial for effective collaboration. By using a real photo, you present yourself as a serious and committed contributor, which in turn encourages others to take your work and interactions seriously. Avoiding non-authentic images ensures that the focus remains on the substance of your contributions rather than on distractions or misunderstandings that might arise from informal or unprofessional visuals. + +3. **Direct Branching and PR Creation**: As a member, you are encourages to create branches and pull requests (PRs) directly within the repository. Please follow the internal branching and code review processes outlined in [guidelines to the development process](https://docs.artemis.cit.tum.de/dev/development-process/development-process.html) and [coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines.html). + +### For External Contributors + +1. **Identity Verification**: External contributions will only be considered if the contributor uses their real name and an authentic profile picture (see above). This ensures accountability and trustworthiness in all external contributions. + +2. **Forking the Repository**: External contributors fork the repository and work on changes in their own branches. + +3. **Submit a Pull Request**: Once your work is complete, submit a pull request for review. Ensure that your branch is up to date with the main branch before submitting. + +4. **Compliance**: Contributions from external contributors that do not adhere to these guidelines may not be accepted. + +### References and Best Practices + +- We align our guidelines with the [GitHub Acceptable Use Policies](https://docs.github.com/en/site-policy/acceptable-use-policies) which stress the importance of authenticity and transparency in user profiles. +- For more insights on contributing to open-source projects, we recommend reviewing the [Open Source Guides by GitHub](https://opensource.guide/). + +By following these guidelines, we foster a collaborative environment built on mutual trust and respect, essential for the success of our project. + +## Contribution Process + +1. **External contributors only**: Fork the Repository and create a branch. +2. **Create a feature branch**: Work on your changes in a separate branch. +3. **Submit a pull request**: Once your work is complete, submit a pull request for review. + +Thank you for your contributions and for helping us maintain a high standard of quality and trust in this project. + + diff --git a/README.md b/README.md index 30ec2419c16d..092d74dcdbb0 100644 --- a/README.md +++ b/README.md @@ -53,22 +53,68 @@ Artemis brings interactive learning to life with instant, individual feedback on ## Roadmap -The Artemis development team prioritizes the following issues in the future. We welcome feature requests from students, tutors, instructors, and administrators. We are happy to discuss any suggestions for improvements. +The Artemis development team prioritizes the following areas in the future. We welcome feature requests from students, tutors, instructors, and administrators. We are happy to discuss any suggestions for improvements. * **Short term**: Further improve the communication features with mobile apps for iOS and Android -* **Short term**: Improve the REST API of the server application +* **Short term**: Add the possibility to use Iris for questions on all exercise types and lectures (partly done) +* **Short term**: Provide GenAI based automatic feedback to modeling, text and programming exercise with Athena +* **Short term**: Improve the LTI integration with Moodle +* **Medium term**: Improve the REST API of the server application +* **Medium term**: Integrate an online IDE (e.g. Eclipse Theia) into Artemis for enhanced user experience * **Medium term**: Add more learning analytics features while preserving data privacy * **Medium term**: Improve the user experience, usability and navigation * **Medium term**: Add automatic generation of hints for programming exercises * **Medium term**: Add GenAI support for reviewing exercises for instructors -* **Medium term**: Add GenAI support for learning analytics -* **Medium term**: Add the possibility to use Iris for questions on all exercise types and lectures +* **Medium term**: Add GenAI support for learning analytics (partly done) * **Long term**: Explore the possibilities of microservices, Kubernetes based deployment, and micro frontends -* **Long term**: Integrated on online IDE (e.g. Eclipse Theia) into Artemis for enhanced user experience * **Long term**: Allow students to take notes on lecture slides and support the automatic updates of lecture slides * **Long term**: Develop an exchange platform for exercises -## Setup, guides, and contributing +## Contributing to This Project + +We welcome contributions from both members of our organization and external contributors. To maintain transparency and trust: + +- **Members**: Must use their full real names and upload a professional and authentic profile picture. Members can directly create branches and PRs in the repository. +- **External Contributors**: Must adhere to our identity guidelines, using real names and authentic profile pictures. Contributions will only be considered if these guidelines are followed. + +We adhere to best practices as recommended by [GitHub's Open Source Guides](https://opensource.guide/) and their [Acceptable Use Policies](https://docs.github.com/en/site-policy/acceptable-use-policies). Thank you for helping us create a respectful and professional environment for everyone involved. + +We follow a pull request contribution model. For detailed guidelines, please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md). Once your pull request is ready to merge, notify the responsible feature maintainer on Slack: + +#### Maintainers + +The following members of the project management team are responsible for specific feature areas in Artemis. Contact them if you have questions or if you want to develop new features in this area. + +| Feature / Aspect | Responsible maintainer | +|--------------------------------|------------------------------------------------------------------------------------| +| Programming exercises | Stephan Krusche ([@krusche](https://github.com/krusche)) | +| Integrated code lifecycle | Stephan Krusche ([@krusche](https://github.com/krusche)) | +| Quiz exercises | Felix Dietrich ([@FelixTJDietrich](https://github.com/FelixTJDietrich)) | +| Modeling exercises (+ Apollon) | Stephan Krusche ([@krusche](https://github.com/krusche)) | +| Text exercises | Maximilian Sölch ([@maximiliansoelch](https://github.com/maximiliansoelch)) | +| File upload exercises | Maximilian Sölch ([@maximiliansoelch](https://github.com/maximiliansoelch)) | +| Exam mode | Stephan Krusche ([@krusche](https://github.com/krusche)) | +| Grading | Maximilian Sölch ([@maximiliansoelch](https://github.com/maximiliansoelch)) | +| Assessment | Maximilian Sölch ([@maximiliansoelch](https://github.com/maximiliansoelch)) | +| Communication | Ramona Beinstingel ([@rabeatwork](https://github.com/rabeatwork)) | +| Notifications | Ramona Beinstingel ([@rabeatwork](https://github.com/rabeatwork)) | +| Team Exercises | Stephan Krusche ([@krusche](https://github.com/krusche)) | +| Lectures | Maximilian Anzinger ([@maximiliananzinger](https://github.com/maximiliananzinger)) | +| Integrated Markdown Editor | Patrick Bassner ([@bassner](https://github.com/bassner)) | +| Plagiarism checks | Markus Paulsen ([@MarkusPaulsen](https://github.com/MarkusPaulsen)) | +| Learning analytics | Maximilian Anzinger ([@maximiliananzinger](https://github.com/maximiliananzinger)) | +| Adaptive learning | Maximilian Anzinger ([@maximiliananzinger](https://github.com/maximiliananzinger)) | +| Learning paths | Maximilian Anzinger ([@maximiliananzinger](https://github.com/maximiliananzinger)) | +| Tutorial Groups | Felix Dietrich ([@FelixTJDietrich](https://github.com/FelixTJDietrich)) | +| Iris | Patrick Bassner ([@bassner](https://github.com/bassner)) | +| Scalability | Matthias Linhuber ([@mtze](https://github.com/mtze)) | +| Usability | Ramona Beinstingel ([@rabeatwork](https://github.com/rabeatwork)) | +| Performance | Ramona Beinstingel ([@rabeatwork](https://github.com/rabeatwork)) | +| Infrastructure | Matthias Linhuber ([@mtze](https://github.com/mtze)) | +| Development process | Felix Dietrich ([@FelixTJDietrich](https://github.com/FelixTJDietrich)) | +| Mobile apps (iOS + Android) | Maximilian Sölch ([@maximiliansoelch](https://github.com/maximiliansoelch)) | + +## Setup and guidelines ### Development setup, coding, and design guidelines @@ -76,6 +122,7 @@ The Artemis development team prioritizes the following issues in the future. We * [Server coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/server/) * [Client coding and design guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/client/) * [Code Review Guidelines](https://docs.artemis.cit.tum.de/dev/development-process/#review) +* [Performance Guidelines](https://docs.artemis.cit.tum.de/dev/guidelines/performance/) ### Documentation @@ -96,46 +143,6 @@ Artemis uses these external tools for user management and the configuration of p If needed, you can configure self service [user registration](https://docs.artemis.cit.tum.de/admin/registration). -### Contributing - -Please read the guide on [how to contribute](CONTRIBUTING.md) to Artemis. - -Once your PR is ready to merge, notify the responsible feature maintainer on Slack: - -#### Maintainers - -The following members of the project management team are responsible for specific feature areas in Artemis. Contact them if you have questions or if you want to develop new features in this area. - -| Feature / Aspect | Maintainer | -|--------------------------------|-----------------------------------------------------------------------------------------------------| -| Programming exercises | [@krusche](https://github.com/krusche) | -| Integrated code lifecycle | [@krusche](https://github.com/krusche) | -| Quiz exercises | [@FelixTJDietrich](https://github.com/FelixTJDietrich) | -| Modeling exercises (+ Apollon) | [@krusche](https://github.com/krusche) | -| Text exercises | [@maximiliansoelch](https://github.com/maximiliansoelch) | -| File upload exercises | [@maximiliansoelch](https://github.com/maximiliansoelch) | -| Exam mode | [@krusche](https://github.com/krusche) | -| Grading | [@maximiliansoelch](https://github.com/maximiliansoelch) | -| Assessment | [@maximiliansoelch](https://github.com/maximiliansoelch) | -| Communication | [@rabeatwork](https://github.com/rabeatwork) | -| Notifications | [@rabeatwork](https://github.com/rabeatwork) | -| Team Exercises | [@krusche](https://github.com/krusche) | -| Lectures | [@maximiliananzinger](https://github.com/maximiliananzinger) | -| Integrated Markdown Editor | [@maximiliansoelch](https://github.com/maximiliansoelch) [@bassner](https://github.com/bassner) | -| Plagiarism checks | [@MarkusPaulsen](https://github.com/MarkusPaulsen) | -| Learning analytics | [@bassner](https://github.com/bassner) | -| Adaptive learning | [@bassner](https://github.com/bassner) [@maximiliananzinger](https://github.com/maximiliananzinger) | -| Learning paths | [@maximiliananzinger](https://github.com/maximiliananzinger) | -| Tutorial Groups | [@FelixTJDietrich](https://github.com/FelixTJDietrich) | -| Iris | [@bassner](https://github.com/bassner) | -| Scalability | [@mtze](https://github.com/mtze) | -| Usability | [@rabeatwork](https://github.com/rabeatwork) | -| Performance | [@rabeatwork](https://github.com/rabeatwork) | -| Infrastructure | [@mtze](https://github.com/mtze) | -| Development process | [@FelixTJDietrich](https://github.com/FelixTJDietrich) | -| Mobile apps (iOS + Android) | [@krusche](https://github.com/krusche) [@maximiliansoelch](https://github.com/maximiliansoelch) | - - ### Building for production To build and optimize the Artemis application for production, run: From 8411fae090ee0c5a1be78672fcc85b6161a9a6cf Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sun, 25 Aug 2024 23:02:39 +0300 Subject: [PATCH 17/60] Development: Update code of conduct --- CODE_OF_CONDUCT.md | 155 +++++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 49 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 89ee014c27e2..d4887bcca43e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,133 @@ -# Contributor Covenant Code of Conduct + +# Artemis Code of Conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission +* Publishing others' private information, such as a physical or email address, + without their explicit permission * Other conduct which could reasonably be considered inappropriate in a - professional setting + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project lead Stephan Krusche at krusche@tum.de. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. -[homepage]: https://www.contributor-covenant.org +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations From 215b72f747e78c6d1ee2de1b8b52f4925ff76f89 Mon Sep 17 00:00:00 2001 From: Asli Aykan <56061820+asliayk@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:18:06 +0200 Subject: [PATCH 18/60] Development: Replace the old translation feature in the client with the new desired approach (#8803) --- .../lti-configuration.component.html | 14 +- ...ification-management-update.component.html | 2 +- ...tem-notification-management.component.html | 12 +- ...pcoming-exams-and-exercises.component.html | 18 +- .../user-management.component.html | 50 ++-- .../assessment-complaint-alert.component.html | 4 +- .../assessment-warning.component.ts | 4 +- ...tructions-assessment-layout.component.html | 6 +- .../complaints-student-view.component.html | 10 +- .../complaints-for-tutor.component.html | 44 +--- .../form/complaints-form.component.html | 26 +- .../list-of-complaints.component.html | 63 +++-- .../request/complaint-request.component.html | 15 +- .../app/core/about-us/about-us.component.html | 20 +- ...-export-confirmation-dialog.component.html | 2 +- .../data-export/data-export.component.html | 6 +- .../competencies-popover.component.html | 10 +- .../competency-card.component.html | 2 +- .../competency-relation-graph.component.html | 10 +- .../import-all-competencies.component.html | 6 +- ...tency-recommendation-detail.component.html | 8 +- .../course-description-form.component.html | 12 +- .../import/competency-search.component.html | 24 +- .../course-scores.component.html | 12 +- ...sment-dashboard-information.component.html | 32 +-- .../assessment-dashboard.component.html | 28 +-- .../exam-assessment-buttons.component.html | 2 +- .../learning-path-legend.component.html | 20 +- .../learning-path.component.html | 2 +- .../learning-path-management.component.html | 2 +- .../course-lti-configuration.component.html | 34 +-- ...it-course-lti-configuration.component.html | 2 +- ...management-exercises-search.component.html | 28 +-- ...course-management-exercises.component.html | 4 +- .../manage/course-management.component.html | 8 +- .../manage/course-update.component.html | 34 ++- .../course-detail-line-chart.component.html | 21 +- .../course-management-card.component.html | 40 ++-- ...rse-management-exercise-row.component.html | 12 +- ...agement-overview-statistics.component.html | 2 +- ...case-instructor-detail-view.component.html | 20 +- ...arism-cases-instructor-view.component.html | 18 +- ...sm-case-student-detail-view.component.html | 10 +- .../tutorial-group-detail.component.html | 2 +- ...al-group-free-days-overview.component.html | 5 +- .../tutorial-group-session-row.component.html | 4 +- ...torial-group-sessions-table.component.html | 34 +-- .../tutorial-group-row.component.html | 4 +- .../tutorial-groups-table.component.html | 30 +-- .../registered-students.component.html | 11 +- ...-tutorial-group-free-period.component.html | 2 +- ...-tutorial-group-free-period.component.html | 2 +- ...rial-group-free-period-form.component.html | 60 ++--- ...oup-free-period-row-buttons.component.html | 2 +- ...oup-free-periods-management.component.html | 12 +- ...al-group-free-periods-table.component.html | 12 +- ...eate-tutorial-group-session.component.html | 2 +- ...edit-tutorial-group-session.component.html | 2 +- ...tutorial-group-session-form.component.html | 42 +--- .../cancellation-modal.component.html | 24 +- ...l-group-session-row-buttons.component.html | 2 +- ...l-group-sessions-management.component.html | 10 +- .../tutorial-groups-checklist.component.html | 26 +- ...torial-groups-configuration.component.html | 6 +- ...torial-groups-configuration.component.html | 2 +- ...l-groups-configuration-form.component.html | 63 +++-- .../create-tutorial-group.component.html | 2 +- .../edit-tutorial-group.component.html | 2 +- .../schedule-form.component.html | 64 ++--- .../tutorial-group-form.component.html | 92 +++----- .../tutorial-group-row-buttons.component.html | 6 +- ...l-groups-course-information.component.html | 4 +- ...torial-groups-import-button.component.html | 6 +- ...-registration-import-dialog.component.html | 25 +- .../tutorial-groups-management.component.html | 10 +- ...scores-average-scores-graph.component.html | 2 +- .../exam-scores/exam-scores.component.html | 145 +++++------- .../manage/exam-management.component.html | 30 +-- .../exam/manage/exam-status.component.html | 46 ++-- .../exam-checklist.component.html | 172 +++++++------- .../exam-edit-working-time.component.html | 2 +- .../manage/exams/exam-detail.component.html | 22 +- .../exam-import/exam-import.component.html | 8 +- .../exam-mode-picker.component.html | 17 +- .../manage/exams/exam-update.component.html | 14 +- .../exercise-group-update.component.html | 4 +- .../exercise-groups.component.html | 56 +++-- .../student-exams.component.html | 4 +- .../students/exam-students.component.html | 2 +- ...udents-upload-images-dialog.component.html | 2 +- ...m-students-attendance-check.component.html | 18 +- .../plagiarism-cases-overview.component.html | 28 ++- .../suspicious-behavior.component.html | 20 +- ...uspicious-sessions-overview.component.html | 14 +- .../test-run-management.component.html | 6 +- .../exam-participation-cover.component.html | 4 +- .../exam-navigation-bar.component.html | 25 +- .../exam-participation.component.html | 8 +- ...file-upload-exam-submission.component.html | 17 +- .../text/text-exam-submission.component.html | 8 +- .../exam-general-information.component.html | 8 +- .../exam-result-summary.component.html | 8 +- .../quiz-exam-summary.component.html | 4 +- .../events/exam-live-event.component.html | 17 +- .../file-upload-assessment.component.html | 4 +- ...file-upload-exercise-update.component.html | 26 +- .../file-upload-submission.component.html | 4 +- ...example-modeling-submission.component.html | 12 +- .../modeling-exercise-update.component.html | 48 ++-- ...ution-entry-generation-step.component.html | 4 +- .../git-diff-report-modal.component.html | 10 +- ...a-category-distribution-chart.component.ts | 47 ++-- ...est-case-distribution-chart.component.html | 49 ++-- ...-exercise-configure-grading.component.html | 6 +- ...xercise-grading-tasks-table.component.html | 4 +- ...ercise-instruction-analysis.component.html | 4 +- .../task-count-warning.component.html | 2 +- ...programming-exercise-detail.component.html | 2 +- ...rogramming-exercise-grading.component.html | 18 +- ...rogramming-exercise-problem.component.html | 12 +- ...de-editor-student-container.component.html | 20 +- .../programming-submission-policy-status.ts | 20 +- .../status/code-editor-status.component.html | 12 +- ...ise-instruction-step-wizard.component.html | 4 +- ...apollon-diagram-create-form.component.html | 22 +- .../apollon-diagram-detail.component.html | 13 +- .../apollon-diagram-list.component.html | 2 +- ...drag-and-drop-question-edit.component.html | 12 +- ...match-percentage-info-modal.component.html | 10 +- ...ltiple-choice-question-edit.component.html | 6 +- .../quiz-exercise-update.component.html | 12 +- .../quiz/manage/quiz-exercise.component.html | 12 +- .../quiz-scoring-info-modal.component.html | 14 +- ...te-multiple-choice-question.component.html | 6 +- .../quiz-re-evaluate.component.html | 4 +- .../short-answer-question-edit.component.html | 48 ++-- .../drag-and-drop-question.component.html | 20 +- .../multiple-choice-question.component.html | 14 +- ...iple-choice-visual-question.component.html | 4 +- .../short-answer-question.component.html | 8 +- .../assessment-progress-label.component.html | 22 +- ...ercise-assessment-dashboard.component.html | 146 ++++-------- .../difficulty-picker.component.html | 24 +- .../example-solution.component.html | 4 +- .../example-submission-import.component.html | 4 +- .../example-submissions.component.html | 2 +- ...rcise-detail-common-actions.component.html | 2 +- ...-exercise-page-with-details.component.html | 29 +-- .../header-participation-page.component.html | 6 +- .../exercise-hint-expandable.component.html | 4 +- ...xercise-hint-student-dialog.component.html | 9 +- .../exercise-info.component.html | 2 +- .../exercise-scores.component.html | 37 ++- .../exercise-update-warning.component.html | 4 +- .../shared/feedback/feedback.component.html | 32 +-- ...ded-in-overall-score-picker.component.html | 15 +- .../participation.component.html | 8 +- .../exercise-update-plagiarism.component.html | 13 +- .../plagiarism-header.component.html | 10 +- .../plagiarism-inspector.component.html | 16 +- .../plagiarism-run-details.component.html | 42 ++-- .../plagiarism-sidebar.component.html | 8 +- .../split-pane-header.component.html | 2 +- .../text-submission-viewer.component.html | 13 +- .../rating-list/rating-list.component.html | 20 +- .../shared/result/result.component.html | 35 +-- ...rading-instructions-details.component.html | 12 +- .../submission-policy-update.component.ts | 6 +- .../team-participation-table.component.html | 12 +- .../teams-import-dialog.component.html | 36 +-- .../shared/team/teams.component.html | 4 +- .../unreferenced-feedback.component.html | 11 +- .../text-assessment-area.component.html | 13 +- .../example-text-submission.component.html | 22 +- .../text-exercise-update.component.html | 22 +- .../feature-overview.component.html | 4 +- .../grading-system/bonus/bonus.component.html | 34 ++- .../detailed-grading-system.component.html | 24 +- .../grading-key-overview.component.html | 2 +- .../grading-key-table.component.html | 10 +- .../grading-system-info-modal.component.html | 26 +- .../grading-system.component.html | 12 +- .../interval-grading-system.component.html | 14 +- .../guided-tour/guided-tour.component.html | 2 +- .../iris/about-iris/about-iris.component.html | 8 +- .../iris-base-chatbot.component.html | 2 +- ...-common-sub-settings-update.component.html | 20 +- .../shared/iris-enabled.component.html | 10 +- .../lecture-attachments.component.html | 6 +- .../attachment-unit-form.component.html | 30 +-- .../attachment-units.component.html | 8 +- .../create-exercise-unit.component.html | 27 ++- .../lecture-unit-layout.component.html | 2 +- .../lecture-unit-management.component.html | 2 +- .../online-unit-form.component.html | 28 +-- .../text-unit-form.component.html | 12 +- .../video-unit-form.component.html | 34 +-- .../app/lecture/lecture-update.component.html | 14 +- .../webapp/app/lecture/lecture.component.html | 2 +- ...lecture-wizard-competencies.component.html | 12 +- ...course-competencies-details.component.html | 6 +- .../course-competencies.component.html | 10 +- ...nversations-code-of-conduct.component.html | 2 +- .../course-conversations.component.html | 4 +- .../course-wide-search.component.html | 8 +- .../channel-form/channel-form.component.html | 74 +++--- .../channels-create-dialog.component.html | 4 +- .../channel-item/channel-item.component.html | 38 ++- .../channels-overview-dialog.component.html | 12 +- ...conversation-add-users-form.component.html | 24 +- ...nversation-add-users-dialog.component.html | 4 +- .../conversation-detail-dialog.component.html | 41 +++- .../conversation-info.component.html | 32 ++- .../conversation-member-row.component.html | 27 ++- .../conversation-members.component.html | 18 +- .../conversation-settings.component.html | 27 ++- ...generic-confirmation-dialog.component.html | 2 +- ...update-text-property-dialog.component.html | 2 +- .../group-chat-create-dialog.component.html | 12 +- ...e-to-one-chat-create-dialog.component.html | 2 +- .../conversation-header.component.html | 10 +- .../conversation-messages.component.html | 17 +- .../course-dashboard.component.html | 2 +- .../course-exercise-row.component.html | 2 +- .../course-lecture-details.component.html | 30 ++- .../course-lecture-row.component.html | 2 +- .../overview/course-overview.component.html | 4 +- ...course-prerequisites-button.component.html | 4 +- .../course-registration-button.component.html | 4 +- .../course-registration-detail.component.html | 8 +- .../course-prerequisites-modal.component.html | 2 +- .../course-registration.component.html | 8 +- .../course-statistics.component.html | 222 +++++++++--------- .../course-tutorial-group-card.component.html | 11 +- .../course-unenrollment-modal.component.html | 20 +- .../app/overview/courses.component.html | 12 +- .../discussion-section.component.html | 28 +-- .../course-exercise-details.component.html | 10 +- .../problem-statement.component.html | 2 +- .../app/overview/header-course.component.html | 4 +- .../submission-result-status.component.html | 14 +- .../exercise-scores-chart.component.html | 6 +- .../code-button/code-button.component.html | 9 +- .../not-released-tag.component.html | 5 +- .../open-code-editor-button.component.html | 4 +- .../reset-repo-button.component.html | 6 +- .../start-practice-mode-button.component.html | 6 +- .../connection-warning.component.html | 4 +- .../consistency-check.component.html | 2 +- .../course-users-selector.component.html | 12 +- .../tutor-leaderboard.component.html | 18 +- .../date-time-picker.component.html | 2 +- .../exercise-categories.component.html | 2 +- .../layouts/navbar/navbar.component.html | 2 +- ...loading-indicator-container.component.html | 2 +- .../markdown-editor.component.html | 20 +- .../message-inline-input.component.html | 6 +- .../message-reply-inline-input.component.html | 6 +- .../posting-content-part.component.html | 4 +- .../posting-content.component.html | 8 +- .../post-create-edit-modal.component.html | 4 +- .../notification-sidebar.component.html | 24 +- ...icipant-scores-distribution.component.html | 8 +- ...tistics-average-score-graph.component.html | 18 +- ...cs-score-distribution-graph.component.html | 2 +- ...ype-ahead-user-search-field.component.html | 2 +- .../users-import-dialog.component.html | 12 +- .../account-information.component.html | 30 +-- .../notification-settings.component.html | 5 +- .../science-settings.component.html | 8 +- .../user-settings-container.component.html | 30 +-- ...sessment-complaint-alert.component.spec.ts | 9 +- .../code-editor-status.component.spec.ts | 33 ++- .../complaints-for-tutor.component.spec.ts | 11 +- ...res-average-scores-graph.component.spec.ts | 5 +- .../exercise-group-update.component.spec.ts | 5 +- .../exam-navigation-bar.component.spec.ts | 5 +- .../text-exam-submission.component.spec.ts | 2 + .../events/exam-live-event.component.spec.ts | 12 +- .../test-run-management.component.spec.ts | 1 + .../component/exercises/shared/result.spec.ts | 3 +- .../detailed-grading-system.component.spec.ts | 2 + ...versation-add-users-form.component.spec.ts | 5 +- .../course-statistics.component.spec.ts | 18 +- ...ramming-exercise-grading.component.spec.ts | 2 + .../shared/code-button.component.spec.ts | 2 + .../course-users-selector.component.spec.ts | 119 +++++----- .../notification-sidebar.component.spec.ts | 9 +- .../component/shared/result.component.spec.ts | 22 +- .../conversation-options.component.spec.ts | 5 +- ...tics-average-score-graph.component.spec.ts | 5 +- .../text-assessment-area.component.spec.ts | 11 +- ...xt-submission-assessment.component.spec.ts | 4 +- ...urse-tutorial-group-card.component.spec.ts | 17 +- ...ial-group-sessions-table.component.spec.ts | 12 +- .../tutorial-groups-table.component.spec.ts | 3 + ...l-group-free-period-form.component.spec.ts | 11 +- ...-free-periods-management.component.spec.ts | 4 +- ...orial-group-session-form.component.spec.ts | 11 +- ...roups-configuration-form.component.spec.ts | 11 +- ...gistration-import-dialog.component.spec.ts | 5 +- 301 files changed, 2269 insertions(+), 2614 deletions(-) diff --git a/src/main/webapp/app/admin/lti-configuration/lti-configuration.component.html b/src/main/webapp/app/admin/lti-configuration/lti-configuration.component.html index 6e026c952a34..32fb9e3112d8 100644 --- a/src/main/webapp/app/admin/lti-configuration/lti-configuration.component.html +++ b/src/main/webapp/app/admin/lti-configuration/lti-configuration.component.html @@ -8,7 +8,7 @@
diff --git a/src/main/webapp/app/admin/system-notification-management/system-notification-management.component.html b/src/main/webapp/app/admin/system-notification-management/system-notification-management.component.html index d6b7c7feca64..867f0c697bb2 100644 --- a/src/main/webapp/app/admin/system-notification-management/system-notification-management.component.html +++ b/src/main/webapp/app/admin/system-notification-management/system-notification-management.component.html @@ -30,19 +30,13 @@

@switch (getNotificationState(notification)) { @case (ACTIVE) { - - {{ 'artemisApp.systemNotification.active' | artemisTranslate }} - + } @case (EXPIRED) { - - {{ 'artemisApp.systemNotification.expired' | artemisTranslate }} - + } @case (SCHEDULED) { - - {{ 'artemisApp.systemNotification.scheduled' | artemisTranslate }} - + } } diff --git a/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.html b/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.html index 1451541419e2..9d928688216a 100644 --- a/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.html +++ b/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.html @@ -10,16 +10,16 @@

- {{ 'artemisApp.upcomingExamsAndExercises.exercise' | artemisTranslate }} + - {{ 'artemisApp.upcomingExamsAndExercises.course' | artemisTranslate }} + - {{ 'artemisApp.upcomingExamsAndExercises.releaseDate' | artemisTranslate }} + - {{ 'artemisApp.upcomingExamsAndExercises.dueDate' | artemisTranslate }} + @@ -61,19 +61,19 @@

- {{ 'artemisApp.upcomingExamsAndExercises.exam' | artemisTranslate }} + - {{ 'artemisApp.upcomingExamsAndExercises.course' | artemisTranslate }} + - {{ 'artemisApp.examManagement.visibleDate' | artemisTranslate }} + - {{ 'artemisApp.examManagement.startDate' | artemisTranslate }} + - {{ 'artemisApp.examManagement.endDate' | artemisTranslate }} + diff --git a/src/main/webapp/app/admin/user-management/user-management.component.html b/src/main/webapp/app/admin/user-management/user-management.component.html index 1c824ea864d0..60a62a3cd70c 100644 --- a/src/main/webapp/app/admin/user-management/user-management.component.html +++ b/src/main/webapp/app/admin/user-management/user-management.component.html @@ -63,9 +63,11 @@

[ngClass]="{ 'btn-secondary': !filters.numberOfAppliedFilters, 'btn-success': !!filters.numberOfAppliedFilters }" > - {{ - 'artemisApp.userManagement.filter.modal.open' | artemisTranslate: { num: filters.numberOfAppliedFilters } - }} +

@@ -227,14 +229,14 @@

@@ -304,7 +300,7 @@
{{ 'artemisApp.userManagement.filter.authority.title' | artemis
-
{{ 'artemisApp.userManagement.filter.origin.title' | artemisTranslate: { num: this.filters.originFilter.size } }}
+
@@ -321,16 +317,18 @@
{{ 'artemisApp.userManagement.filter.origin.title' | artemisTra }
  • - +
  • -
    {{ 'artemisApp.userManagement.filter.registrationNumber.title' | artemisTranslate: { num: this.filters.registrationNumberFilter.size } }}
    +
    @@ -360,16 +358,14 @@
    {{ 'artemisApp.userManagement.filter.registrationNumber.title' (click)="this.toggleRegistrationNumberFilter()" [checked]="this.filters.registrationNumberFilter.size === 0" /> - +
    -
    {{ 'artemisApp.userManagement.filter.status.title' | artemisTranslate: { num: this.filters.statusFilter.size } }}
    +
    @@ -386,9 +382,7 @@
    {{ 'artemisApp.userManagement.filter.status.title' | artemisTra }
  • - +
  • @@ -396,9 +390,7 @@
    {{ 'artemisApp.userManagement.filter.status.title' | artemisTra
    } diff --git a/src/main/webapp/app/complaints/complaints-for-tutor/complaints-for-tutor.component.html b/src/main/webapp/app/complaints/complaints-for-tutor/complaints-for-tutor.component.html index 0997b352dbbd..97bd1ae26257 100644 --- a/src/main/webapp/app/complaints/complaints-for-tutor/complaints-for-tutor.component.html +++ b/src/main/webapp/app/complaints/complaints-for-tutor/complaints-for-tutor.component.html @@ -1,25 +1,20 @@ @if (isLoading) {
    - {{ 'loading' | artemisTranslate }} +
    } @if (!isLoading && complaint) { -

    - {{ complaint.complaintType === ComplaintType.MORE_FEEDBACK ? ('artemisApp.moreFeedback.review' | artemisTranslate) : ('artemisApp.complaint.review' | artemisTranslate) }} -

    +

    } @if (!isLoading && complaint) {
    @if (handled) { -
    - {{ - complaint.complaintType === ComplaintType.MORE_FEEDBACK - ? ('artemisApp.moreFeedback.alreadyHandled' | artemisTranslate) - : ('artemisApp.complaint.complaintAlreadyHandled' | artemisTranslate) - }} -
    +
    }
    @if (showLockDuration) { @@ -35,21 +30,13 @@

    } @if (lockedByCurrentUser) { - + }

    - {{ - complaint.complaintType === ComplaintType.MORE_FEEDBACK - ? ('artemisApp.moreFeedback.title' | artemisTranslate) - : ('artemisApp.complaint.title' | artemisTranslate) - }} - + @if (handled) { @if (complaint?.accepted) { @@ -71,13 +58,9 @@

    @if (handled || isAllowedToRespond) {
    -

    - {{ - complaint.complaintType === ComplaintType.MORE_FEEDBACK - ? ('artemisApp.moreFeedbackResponse.title' | artemisTranslate) - : ('artemisApp.complaintResponse.title' | artemisTranslate) - }} -

    +

    diff --git a/src/main/webapp/app/complaints/list-of-complaints/list-of-complaints.component.html b/src/main/webapp/app/complaints/list-of-complaints/list-of-complaints.component.html index 0651cc2ad7e5..ff642a21befc 100644 --- a/src/main/webapp/app/complaints/list-of-complaints/list-of-complaints.component.html +++ b/src/main/webapp/app/complaints/list-of-complaints/list-of-complaints.component.html @@ -3,10 +3,10 @@

    @if (complaintType === ComplaintType.COMPLAINT) { - {{ 'artemisApp.complaint.listOfComplaints.title' | artemisTranslate }} + } @if (complaintType === ComplaintType.MORE_FEEDBACK) { - {{ 'artemisApp.moreFeedback.list.title' | artemisTranslate }} + }

    @@ -15,16 +15,16 @@

    @if (!allComplaintsForTutorLoaded && complaintType === ComplaintType.COMPLAINT) { - {{ 'artemisApp.complaint.listOfComplaints.loadAllComplaintsExplanation' | artemisTranslate }} + } @if (!allComplaintsForTutorLoaded && complaintType === ComplaintType.MORE_FEEDBACK) { - {{ 'artemisApp.moreFeedback.list.loadAllRequestsExplanation' | artemisTranslate }} + } @if (allComplaintsForTutorLoaded && complaintType === ComplaintType.COMPLAINT) { - {{ 'artemisApp.complaint.listOfComplaints.allComplaintsLoaded' | artemisTranslate }} + } @if (allComplaintsForTutorLoaded && complaintType === ComplaintType.MORE_FEEDBACK) { - {{ 'artemisApp.moreFeedback.list.allRequestsLoaded' | artemisTranslate }} + } @if (!allComplaintsForTutorLoaded) { } @@ -59,13 +59,12 @@

    />

    @@ -80,48 +79,48 @@

    - {{ 'artemisApp.complaint.listOfComplaints.exercise' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.submissionId' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.assessorName' | artemisTranslate }} + @if (course?.isAtLeastInstructor) { - {{ 'artemisApp.complaint.listOfComplaints.studentLogin' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.studentName' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.reviewerName' | artemisTranslate }} + } - {{ 'artemisApp.complaint.listOfComplaints.dateAndTime' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.responseTime' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.status' | artemisTranslate }} + - {{ 'artemisApp.locks.lockStatus' | artemisTranslate }} + - {{ 'artemisApp.complaint.listOfComplaints.actions' | artemisTranslate }} + @@ -166,16 +165,16 @@

    @if (complaint.accepted === undefined) { - {{ 'artemisApp.complaint.listOfComplaints.noReply' | artemisTranslate }} + } @if (complaint.accepted === true && complaintType === ComplaintType.COMPLAINT) { - {{ 'artemisApp.complaint.listOfComplaints.accepted' | artemisTranslate }} + } @if (complaint.accepted === true && complaintType === ComplaintType.MORE_FEEDBACK) { - {{ 'artemisApp.moreFeedback.accepted' | artemisTranslate }} + } @if (complaint.accepted === false) { - {{ 'artemisApp.complaint.listOfComplaints.rejected' | artemisTranslate }} + } @@ -185,10 +184,10 @@

    @@ -199,10 +198,10 @@

    @if (complaintType === ComplaintType.COMPLAINT) { - {{ 'artemisApp.exerciseAssessmentDashboard.noComplaints' | artemisTranslate }} + } @if (complaintType === ComplaintType.MORE_FEEDBACK) { - {{ 'artemisApp.exerciseAssessmentDashboard.noMoreFeedbackRequests' | artemisTranslate }} + }

    diff --git a/src/main/webapp/app/complaints/request/complaint-request.component.html b/src/main/webapp/app/complaints/request/complaint-request.component.html index 5c3b8f448f1c..2f86094c7345 100644 --- a/src/main/webapp/app/complaints/request/complaint-request.component.html +++ b/src/main/webapp/app/complaints/request/complaint-request.component.html @@ -7,18 +7,13 @@ }} {{ complaint.submittedTime | artemisTimeAgo }} @if (complaint.accepted === true) { - - {{ - complaint.complaintType === ComplaintType.COMPLAINT - ? ('artemisApp.complaint.acceptedLong' | artemisTranslate) - : ('artemisApp.moreFeedback.acceptedLong' | artemisTranslate) - }} - + } @if (complaint.accepted === false) { - - {{ 'artemisApp.complaint.rejectedLong' | artemisTranslate }} - + }

    - +
    - +

    [ngModel]="hideOptional" (ngModelChange)="triggerOptionalExercises()" /> - +

    } @@ -120,33 +116,33 @@

    - {{ 'artemisApp.assessmentDashboard.exerciseType' | artemisTranslate }} + - {{ 'artemisApp.assessmentDashboard.exercise' | artemisTranslate }} + @if (!isTestRun) { - {{ 'artemisApp.assessmentDashboard.yourStatus' | artemisTranslate }} + } - {{ 'artemisApp.assessmentDashboard.exerciseAverageRating' | artemisTranslate }} + @if (!isExamMode) { - {{ 'artemisApp.assessmentDashboard.exerciseDueDate' | artemisTranslate }} + } @if (!isExamMode) { - {{ 'artemisApp.assessmentDashboard.assessmentsDueDate' | artemisTranslate }} + } - {{ 'artemisApp.assessmentDashboard.actions' | artemisTranslate }} + @@ -241,7 +237,7 @@

    @if (course && course.isAtLeastInstructor && tutorIssues.length > 0) {
    -

    {{ 'artemisApp.assessmentDashboard.tutorPerformanceIssues.title' | artemisTranslate }}

    +

    @for (issue of tutorIssues; track issue) {
      @if (issue.averageTutorValue < issue.allowedRange.lowerBound) { @@ -278,10 +274,10 @@

      {{ 'artemisApp.assessmentDashboard.tutorPerformanceIssues.title' | artemisTr }
      @if (!isExamMode) { -

      {{ 'artemisApp.assessmentDashboard.tutorLeaderboard.courseTitle' | artemisTranslate }}

      +

      } @if (isExamMode) { -

      {{ 'artemisApp.assessmentDashboard.tutorLeaderboard.examTitle' | artemisTranslate }}

      +

      }
      diff --git a/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.html b/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.html index 988ad7835bce..1bae6b366f55 100644 --- a/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.html +++ b/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.html @@ -3,7 +3,7 @@ - {{ 'artemisApp.examManagement.gradingSystem' | artemisTranslate }} +

    } @@ -13,9 +11,7 @@
    - - {{ 'artemisApp.learningPath.graph.legend.matchStart.title' | artemisTranslate }} - +
    } @@ -23,9 +19,7 @@
    - - {{ 'artemisApp.learningPath.graph.legend.matchEnd.title' | artemisTranslate }} - +
    } @@ -33,9 +27,7 @@
    - - {{ 'artemisApp.learningPath.graph.legend.learningObject.title' | artemisTranslate }} - +
    } @@ -43,9 +35,7 @@
    - - {{ 'artemisApp.learningPath.graph.legend.completedLearningObject.title' | artemisTranslate }} - +
    } diff --git a/src/main/webapp/app/course/learning-paths/learning-path-graph/learning-path.component.html b/src/main/webapp/app/course/learning-paths/learning-path-graph/learning-path.component.html index 396b2735560b..864bcc2920b0 100644 --- a/src/main/webapp/app/course/learning-paths/learning-path-graph/learning-path.component.html +++ b/src/main/webapp/app/course/learning-paths/learning-path-graph/learning-path.component.html @@ -1,7 +1,7 @@ @if (isLoading) {
    - {{ 'loading' | artemisTranslate }} +
    } @else { diff --git a/src/main/webapp/app/course/learning-paths/learning-path-management/learning-path-management.component.html b/src/main/webapp/app/course/learning-paths/learning-path-management/learning-path-management.component.html index 061c611f6b93..c8a10304da15 100644 --- a/src/main/webapp/app/course/learning-paths/learning-path-management/learning-path-management.component.html +++ b/src/main/webapp/app/course/learning-paths/learning-path-management/learning-path-management.component.html @@ -1,7 +1,7 @@ @if (isLoading) {
    - {{ 'loading' | artemisTranslate }} +
    } diff --git a/src/main/webapp/app/course/manage/course-lti-configuration/course-lti-configuration.component.html b/src/main/webapp/app/course/manage/course-lti-configuration/course-lti-configuration.component.html index 8c267652beff..b7252be6dc5d 100644 --- a/src/main/webapp/app/course/manage/course-lti-configuration/course-lti-configuration.component.html +++ b/src/main/webapp/app/course/manage/course-lti-configuration/course-lti-configuration.component.html @@ -16,28 +16,28 @@