diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d56abbf304 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto eol=lf diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 124fe4c2ae..40d35b9eee 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -10,38 +10,40 @@ on: # deployment: # workflow_dispatch: jobs: - docker-deploy-development-image: - if: github.repository_owner == 'doubtfire-lms' - environment: deployment-secrets - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - if: github.event_name != 'pull_request' - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Setup meta for development image - id: docker_meta - uses: docker/metadata-action@v5 - with: - images: lmsdoubtfire/doubtfire-web - tags: | - type=semver,pattern={{major}}.{{minor}}.x-dev - - name: Build and push web server - id: docker_build - uses: docker/build-push-action@v5 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.docker_meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} + # docker-deploy-development-image: + # if: github.repository_owner == 'doubtfire-lms' + # environment: deployment-secrets + # runs-on: ubuntu-latest + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # with: + # submodules: recursive + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + # - name: Login to DockerHub + # uses: docker/login-action@v3 + # if: github.event_name != 'pull_request' + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + # - name: Setup meta for development image + # id: docker_meta + # uses: docker/metadata-action@v5 + # with: + # images: lmsdoubtfire/doubtfire-web + # tags: | + # type=semver,pattern={{major}}.{{minor}}.x-dev + # - name: Build and push web server + # id: docker_build + # uses: docker/build-push-action@v5 + # with: + # context: . + # push: ${{ github.event_name != 'pull_request' }} + # tags: ${{ steps.docker_meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} + # - name: Image digest + # run: echo ${{ steps.docker_build.outputs.digest }} docker-web-server: if: github.repository_owner == 'doubtfire-lms' environment: deployment-secrets @@ -49,6 +51,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub diff --git a/.gitignore b/.gitignore index 9abc43ca67..c5c729aef4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ vendor/ .sass-cache* .bundle* tmp.scss -.vscode .tscache a.env dist/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..f259c41cca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "JPlag-Report-Viewer"] + path = JPlag-Report-Viewer + url = https://github.com/doubtfire-lms/jplag-report-viewer-static.git diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..8582900e71 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "files.eol": "\n" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ca7d64128..9a119c3b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,1385 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.0.1-22](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-21...v10.0.1-22) (2026-03-23) + + +### Features + +* display portfolio submission time ([d717b27](https://github.com/b0ink/doubtfire-deploy/commit/d717b270eb80c0b0245e6b39f0b3f0567c379512)) +* require discussion before marking complete ([#1103](https://github.com/b0ink/doubtfire-deploy/issues/1103)) ([86ae886](https://github.com/b0ink/doubtfire-deploy/commit/86ae8865268ee19e4b3430ff679358cc075e1346)) + + +### Bug Fixes + +* avoid rendering the staff list twice ([9e5be59](https://github.com/b0ink/doubtfire-deploy/commit/9e5be591b9a0cf72d01efa5e28e5b2b9e7eba043)) +* only render if submission date is valid ([04986a0](https://github.com/b0ink/doubtfire-deploy/commit/04986a0e501f0185dbd199b8d2554133217f7e75)) + +### [10.0.1-21](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-20...v10.0.1-21) (2026-03-13) + +### [10.0.1-20](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-19...v10.0.1-20) (2026-03-13) + +### [10.0.1-19](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-18...v10.0.1-19) (2026-03-13) + + +### Features + +* view submission history + zip file editor ([#1104](https://github.com/b0ink/doubtfire-deploy/issues/1104)) ([d706f09](https://github.com/b0ink/doubtfire-deploy/commit/d706f0918285a2c6d69c6240a93b41e88506f771)) + +### [10.0.1-18](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-17...v10.0.1-18) (2026-03-11) + + +### Bug Fixes + +* convert emojis in submission comment to string with colons ([#1105](https://github.com/b0ink/doubtfire-deploy/issues/1105)) ([7c508cb](https://github.com/b0ink/doubtfire-deploy/commit/7c508cba8695fcd7b6df4aaa53a70066ecb137f3)) +* dont subtract tutor note count for reading your own notes ([8fe6171](https://github.com/b0ink/doubtfire-deploy/commit/8fe61718c0e263fa965b861763337af27c175b36)) + +### [10.0.1-17](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-16...v10.0.1-17) (2026-03-06) + + +### Bug Fixes + +* empty prompts layout ([c77325a](https://github.com/b0ink/doubtfire-deploy/commit/c77325a2992d0b326bdeb27cd00a955aaa19811c)) + +### [10.0.1-16](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-15...v10.0.1-16) (2026-03-04) + +### [10.0.1-15](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-14...v10.0.1-15) (2026-03-04) + +### [10.0.1-14](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-13...v10.0.1-14) (2026-03-03) + + +### Features + +* view tutor notes from unit staff editor ([011980d](https://github.com/b0ink/doubtfire-deploy/commit/011980ddebb4caddaebb380aae4825930c077122)) + +### [10.0.1-13](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-12...v10.0.1-13) (2026-03-02) + + +### Features + +* add snooze moderation action ([#1096](https://github.com/b0ink/doubtfire-deploy/issues/1096)) ([bdcefda](https://github.com/b0ink/doubtfire-deploy/commit/bdcefda81e4acdef56ebe9f228632f26a904287c)) + +### [10.0.1-12](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-11...v10.0.1-12) (2026-03-02) + +### [10.0.1-11](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-10...v10.0.1-11) (2026-02-28) + + +### Bug Fixes + +* ensure deadline is returned ([6629a5f](https://github.com/b0ink/doubtfire-deploy/commit/6629a5f4b9834009dabf19a60a36c1289126034d)) + +### [10.0.1-10](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-9...v10.0.1-10) (2026-02-26) + + +### Features + +* display available storage for docker images ([#1092](https://github.com/b0ink/doubtfire-deploy/issues/1092)) ([81ebd34](https://github.com/b0ink/doubtfire-deploy/commit/81ebd3488d20a1e057c24b37190f4eea99bad9ec)) + +### [10.0.1-9](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-8...v10.0.1-9) (2026-02-25) + + +### Bug Fixes + +* typo ([4ecfe27](https://github.com/b0ink/doubtfire-deploy/commit/4ecfe27c91104c746ac8a4f9059030d5475776bb)) + +### [10.0.1-8](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-7...v10.0.1-8) (2026-02-25) + + +### Features + +* overflow marking ([#1086](https://github.com/b0ink/doubtfire-deploy/issues/1086)) ([e047988](https://github.com/b0ink/doubtfire-deploy/commit/e047988c4fff787852d1cc5a041cb48e11ee57f8)) + +### [10.0.1-7](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-6...v10.0.1-7) (2026-02-25) + + +### Bug Fixes + +* ensure timestamp is normalised to start of day ([671c391](https://github.com/b0ink/doubtfire-deploy/commit/671c3916797dc5ab680b9dac52ae68626e49d351)) + +### [10.0.1-6](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-5...v10.0.1-6) (2026-02-24) + +### [10.0.1-5](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-4...v10.0.1-5) (2026-02-24) + + +### Features + +* per grade start dates ([#1090](https://github.com/b0ink/doubtfire-deploy/issues/1090)) ([a35019a](https://github.com/b0ink/doubtfire-deploy/commit/a35019aa4011fce7808da8cc1481fae7635aac69)) + +### [10.0.1-4](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-3...v10.0.1-4) (2026-02-23) + + +### Features + +* allow custom target dates per target grade ([#1089](https://github.com/b0ink/doubtfire-deploy/issues/1089)) ([79b5af6](https://github.com/b0ink/doubtfire-deploy/commit/79b5af6bf05419e05dbef69e6ef1f72bfc85097c)) + +### [10.0.1-3](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-2...v10.0.1-3) (2026-02-21) + +### [10.0.1-2](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-1...v10.0.1-2) (2026-02-19) + + +### Bug Fixes + +* set min width for mentor dropdown ([75cc1b3](https://github.com/b0ink/doubtfire-deploy/commit/75cc1b3569d17cd54e71f86874addb4bc34d566f)) + +### [10.0.1-1](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-0...v10.0.1-1) (2026-02-18) + + +### Features + +* tutor notes + mentorship + moderation + escalation ([#1068](https://github.com/b0ink/doubtfire-deploy/issues/1068)) ([48f4db7](https://github.com/b0ink/doubtfire-deploy/commit/48f4db730f06e349f5e3c791f1972d23b0f8573f)) + + +### Bug Fixes + +* ensure tutor notes view extends full height ([c872ed7](https://github.com/b0ink/doubtfire-deploy/commit/c872ed766bf493456da56e33dcda48a90ed3f6ce)) + +### [10.0.1-0](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0...v10.0.1-0) (2026-02-17) + +## [10.0.0](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-73...v10.0.0) (2026-02-12) + +## [10.0.0-73](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-72...v10.0.0-73) (2026-02-12) + +## [10.0.0-72](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-71...v10.0.0-72) (2026-02-12) + + +### Bug Fixes + +* null safe user access ([f6aeecc](https://github.com/b0ink/doubtfire-deploy/commit/f6aeecc6c2c79909ca859422e7d9b3bc65ef6456)) + +## [10.0.0-71](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-70...v10.0.0-71) (2026-02-11) + + +### Features + +* download staff notes csv ([#1062](https://github.com/b0ink/doubtfire-deploy/issues/1062)) ([6dcfe95](https://github.com/b0ink/doubtfire-deploy/commit/6dcfe952f0415fb1327b738137f817a0fcfa0488)) +* migrate to jplag report viewer v6.3.0 ([#1082](https://github.com/b0ink/doubtfire-deploy/issues/1082)) ([697588b](https://github.com/b0ink/doubtfire-deploy/commit/697588b98e28ec663f4982c49f18fe8109ba7c34)) + +## [10.0.0-70](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-69...v10.0.0-70) (2026-01-05) + + +### Bug Fixes + +* skip query for unsaved task definition ([a6bdd22](https://github.com/b0ink/doubtfire-deploy/commit/a6bdd22ff864e72c679fae1844345963447fdf08)) + +## [10.0.0-69](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-68...v10.0.0-69) (2026-01-05) + + +### Features + +* attention required task status ([#1061](https://github.com/b0ink/doubtfire-deploy/issues/1061)) ([15365ed](https://github.com/b0ink/doubtfire-deploy/commit/15365ed4f42af790af9a9ae24dae42f041dff1df)) +* display number of stuff notes in tutor discussion ([2674d4e](https://github.com/b0ink/doubtfire-deploy/commit/2674d4e5ade26e5420b87518f4cd9da909ec7246)) +* overseer pipeline ([#1064](https://github.com/b0ink/doubtfire-deploy/issues/1064)) ([7cb8fc7](https://github.com/b0ink/doubtfire-deploy/commit/7cb8fc7471f0402c562fb8a0b87df672ceb22ea3)) +* project task planner gantt chart ([#1051](https://github.com/b0ink/doubtfire-deploy/issues/1051)) ([4f60792](https://github.com/b0ink/doubtfire-deploy/commit/4f607926e3ac305316a05607fda7f7bff7faec00)) + +## [10.0.0-68](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-67...v10.0.0-68) (2025-12-08) + + +### Bug Fixes + +* only trim if valid ([fbc63b0](https://github.com/b0ink/doubtfire-deploy/commit/fbc63b0308d87d921e1d74788e8da6031443e57e)) + +## [10.0.0-67](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-66...v10.0.0-67) (2025-12-03) + + +### Features + +* allow sidekiq web access ([#1053](https://github.com/b0ink/doubtfire-deploy/issues/1053)) ([6651279](https://github.com/b0ink/doubtfire-deploy/commit/6651279c49f431dbddf6fd5d810440ae7b3b9898)) + +## [10.0.0-66](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-65...v10.0.0-66) (2025-12-03) + + +### Features + +* discussion prompts ([#1042](https://github.com/b0ink/doubtfire-deploy/issues/1042)) ([730ffd0](https://github.com/b0ink/doubtfire-deploy/commit/730ffd0c3f79a5ad42c0c59c2f2c2a901ab0d702)) + + +### Bug Fixes + +* correctly set rollover end date ([0611be0](https://github.com/b0ink/doubtfire-deploy/commit/0611be04e8fe7e75ae07504945a2984839475e3a)) + +## [10.0.0-65](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-64...v10.0.0-65) (2025-11-25) + + +### Bug Fixes + +* typo ([bdcd75d](https://github.com/b0ink/doubtfire-deploy/commit/bdcd75d91d5ddc7d9a60317bd91289a7242251e1)) + +## [10.0.0-64](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-63...v10.0.0-64) (2025-11-25) + + +### Bug Fixes + +* avoid calling window to open project in new tab ([9ab015d](https://github.com/b0ink/doubtfire-deploy/commit/9ab015d168cf7e421500910766b9e6fb0bf907f5)) +* use new google fonts api for proper weight loading ([#1039](https://github.com/b0ink/doubtfire-deploy/issues/1039)) ([40f2640](https://github.com/b0ink/doubtfire-deploy/commit/40f2640e6579536cef8e82e9476733083b82bac1)) + +## [10.0.0-63](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-62...v10.0.0-63) (2025-11-10) + + +### Features + +* open project dashboard from portfolios view ([5b4b097](https://github.com/b0ink/doubtfire-deploy/commit/5b4b097a9b189e5a816695cce7438104f1144283)), closes [#1040](https://github.com/b0ink/doubtfire-deploy/issues/1040) + +## [10.0.0-62](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-61...v10.0.0-62) (2025-11-06) + + +### Features + +* restrict assessments to tutors in the same tutorial stream ([#1033](https://github.com/b0ink/doubtfire-deploy/issues/1033)) ([29fbc14](https://github.com/b0ink/doubtfire-deploy/commit/29fbc1498b0d48811cb59c5f2a66871fbac06849)) + +## [10.0.0-61](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-60...v10.0.0-61) (2025-11-06) + +## [10.0.0-60](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-59...v10.0.0-60) (2025-11-05) + + +### Features + +* upload grades csv ([#1038](https://github.com/b0ink/doubtfire-deploy/issues/1038)) ([c67ceaa](https://github.com/b0ink/doubtfire-deploy/commit/c67ceaa84d02bb71626890fc28bb4aaea164b952)) + +## [10.0.0-59](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-58...v10.0.0-59) (2025-11-04) + + +### Bug Fixes + +* require comment for new evidence ([58ec499](https://github.com/b0ink/doubtfire-deploy/commit/58ec499a8d59c7202f591de661551d8a32c37527)) +* require comment for new evidence ([c5397fc](https://github.com/b0ink/doubtfire-deploy/commit/c5397fc5c444e76b431aa5d6487553c60e711c2e)) + +## [10.0.0-58](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-57...v10.0.0-58) (2025-11-01) + +## [10.0.0-57](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-56...v10.0.0-57) (2025-10-30) + + +### Features + +* open similarities from project dashboard ([#1035](https://github.com/b0ink/doubtfire-deploy/issues/1035)) ([ec0af0c](https://github.com/b0ink/doubtfire-deploy/commit/ec0af0cbe47392d6542d9741e1131954195d407f)) + + +### Bug Fixes + +* enable submission button for 'need help' trigger ([#1034](https://github.com/b0ink/doubtfire-deploy/issues/1034)) ([07de5b1](https://github.com/b0ink/doubtfire-deploy/commit/07de5b1e34f78f83c1418399f45e8c754aea530a)) +* typo ([2712a68](https://github.com/b0ink/doubtfire-deploy/commit/2712a68f6031794c571a7ee5866c653bf67de1dd)) + +## [10.0.0-56](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-55...v10.0.0-56) (2025-10-23) + + +### Bug Fixes + +* ensure grade has been selected ([32e03d1](https://github.com/b0ink/doubtfire-deploy/commit/32e03d111e61df42a9c67cb9e68d271f9300d5bc)) + +## [10.0.0-55](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-54...v10.0.0-55) (2025-10-20) + + +### Features + +* display task count in inbox ([#1025](https://github.com/b0ink/doubtfire-deploy/issues/1025)) ([3858e37](https://github.com/b0ink/doubtfire-deploy/commit/3858e3792fef3f0542d954e213987484ac97a990)) + + +### Bug Fixes + +* display correct marking session details ([c49ffed](https://github.com/b0ink/doubtfire-deploy/commit/c49ffeddedb2b79c39252770692e7df9dcd97bfc)) +* typo ([8a1dd1a](https://github.com/b0ink/doubtfire-deploy/commit/8a1dd1ac806c5acbbf8d1ccf7bdcb6af1c68dd14)) + +## [10.0.0-54](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-53...v10.0.0-54) (2025-10-17) + +## [10.0.0-53](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-52...v10.0.0-53) (2025-10-17) + +## [10.0.0-52](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-51...v10.0.0-52) (2025-10-17) + + +### Features + +* campus timezone ([#1022](https://github.com/b0ink/doubtfire-deploy/issues/1022)) ([4384b37](https://github.com/b0ink/doubtfire-deploy/commit/4384b376eaedf8ab66febec4c0ada53111311ff0)) +* download marking sessions for tutor ([e3fbe44](https://github.com/b0ink/doubtfire-deploy/commit/e3fbe4404661eb16b9c0e5ba19a1369dac1fb5b0)) + + +### Bug Fixes + +* display tutor name ([8956020](https://github.com/b0ink/doubtfire-deploy/commit/89560205d7316c53d77f376b5f7cfff5bf99e9c6)) +* filter out students from unit staff editor ([#1018](https://github.com/b0ink/doubtfire-deploy/issues/1018)) ([5c0c997](https://github.com/b0ink/doubtfire-deploy/commit/5c0c9974569e720a6c95aa8333c2a38d0ab4a1b0)) +* re-enable user filtering on click ([697daf2](https://github.com/b0ink/doubtfire-deploy/commit/697daf26693f20f61dcfbbeb0597a02715c9512d)) + +## [10.0.0-51](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-50...v10.0.0-51) (2025-10-14) + + +### Bug Fixes + +* unlock tasks when prerequisite requires rff and task is in aip state ([173d8c2](https://github.com/b0ink/doubtfire-deploy/commit/173d8c25375e231b25e64a04c1e3d2aedf741300)) + +## [10.0.0-50](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-49...v10.0.0-50) (2025-10-13) + + +### Features + +* jplag base code ([#1010](https://github.com/b0ink/doubtfire-deploy/issues/1010)) ([9a7a860](https://github.com/b0ink/doubtfire-deploy/commit/9a7a860fe799e351831e2a3f9701792792b76b38)) + +## [10.0.0-49](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-48...v10.0.0-49) (2025-10-12) + + +### Features + +* display session start and end time ([bb548b9](https://github.com/b0ink/doubtfire-deploy/commit/bb548b92d04bb7b8665444e7935317bc4b6a0981)) + +## [10.0.0-48](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-47...v10.0.0-48) (2025-10-12) + + +### Features + +* add tutor times summary download ([#1015](https://github.com/b0ink/doubtfire-deploy/issues/1015)) ([2b4afe2](https://github.com/b0ink/doubtfire-deploy/commit/2b4afe24e3f8139fec23337facc7656eec9a9d3a)) + + +### Bug Fixes + +* add assess in portfolio tasks as completed tasks in burndown chart ([8d36c94](https://github.com/b0ink/doubtfire-deploy/commit/8d36c94f03563a0924cfeb7d2d9e8dd911b65960)) + +## [10.0.0-47](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-46...v10.0.0-47) (2025-09-25) + + +### Features + +* add observer only ui ([bfbcee9](https://github.com/b0ink/doubtfire-deploy/commit/bfbcee98cfa4888241c5956372d004ec1cd813cb)) + +## [10.0.0-46](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-45...v10.0.0-46) (2025-09-24) + +## [10.0.0-45](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-44...v10.0.0-45) (2025-09-22) + + +### Bug Fixes + +* check for valid unit ([bfae1ad](https://github.com/b0ink/doubtfire-deploy/commit/bfae1ad69bb767cdad47dd8fac35cc84e5134534)) + +## [10.0.0-44](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-43...v10.0.0-44) (2025-09-18) + +## [10.0.0-43](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-42...v10.0.0-43) (2025-09-17) + + +### Bug Fixes + +* remove /api from host url ([5889edc](https://github.com/b0ink/doubtfire-deploy/commit/5889edc35bb427dfd4defefa7b77e8c81cd6dd7c)) + +## [10.0.0-42](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-41...v10.0.0-42) (2025-09-17) + + +### Features + +* display result of student imports ([e0503f4](https://github.com/b0ink/doubtfire-deploy/commit/e0503f424dfbef49e68b4e2f697e8d135120634e)) +* enable unit linking to lms context using deeplink ([73de1f1](https://github.com/b0ink/doubtfire-deploy/commit/73de1f1c68223c863c35198b773f0bdeaa1f549e)) +* init lti integration ([248be93](https://github.com/b0ink/doubtfire-deploy/commit/248be93e7c8b5ff060957e500b6a4943882f456c)) +* sync enrolments for all lti members ([5ec499f](https://github.com/b0ink/doubtfire-deploy/commit/5ec499f37b93f2b4bd56d145501fd55ab6af45e6)) +* sync grades for all members ([0f5daa8](https://github.com/b0ink/doubtfire-deploy/commit/0f5daa852f4c3750367f7d2c3f9b0c07ffbfed3f)) +* unauthorised lti banner ([12e65d8](https://github.com/b0ink/doubtfire-deploy/commit/12e65d8f1609f2030b25347beb1c0e06f513f65c)) + + +### Bug Fixes + +* forward correct lti token ([e95544e](https://github.com/b0ink/doubtfire-deploy/commit/e95544e2e158affefafd2fc0fe9657bf47c200db)) + +## [10.0.0-41](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-40...v10.0.0-41) (2025-09-15) + +## [10.0.0-40](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-39...v10.0.0-40) (2025-09-15) + + +### Features + +* assess in portfolio status ([ada4a21](https://github.com/b0ink/doubtfire-deploy/commit/ada4a21c945018abeb9ca1169e48fdd822a27322)) +* ensure complete button updates aip only tasks to working on it ([c8dd020](https://github.com/b0ink/doubtfire-deploy/commit/c8dd020a5e572765f7710c266ae2b20563ab05c2)) +* send automated message when set back to working on it ([a858d3a](https://github.com/b0ink/doubtfire-deploy/commit/a858d3a7b2f41ac7478d4917d2d2f6c68a167e6e)) +* submission type modal ([52f7d40](https://github.com/b0ink/doubtfire-deploy/commit/52f7d404ef154ff27c0ba887c8321360df95ddb6)) + + +### Bug Fixes + +* typo ([2a2e4a4](https://github.com/b0ink/doubtfire-deploy/commit/2a2e4a41e6ea20152632a9f82ca1723d9a6b56cc)) +* wording ([6291bd6](https://github.com/b0ink/doubtfire-deploy/commit/6291bd61ccc4ff45c708300d0a5014a59a565414)) + +## [10.0.0-39](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-38...v10.0.0-39) (2025-09-10) + + +### Features + +* display warning above task sheet for incomplete prerequisites ([86433bb](https://github.com/b0ink/doubtfire-deploy/commit/86433bb18e6ff9b024d7c397b8744618721b602f)) + +## [10.0.0-38](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-37...v10.0.0-38) (2025-09-09) + + +### Bug Fixes + +* ensure task prerequisites are correctly cached ([3945f4e](https://github.com/b0ink/doubtfire-deploy/commit/3945f4e2ecff1a1d79662c099baf745bfd6f4b7d)) + +## [10.0.0-37](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-36...v10.0.0-37) (2025-09-09) + +## [10.0.0-36](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-35...v10.0.0-36) (2025-09-09) + +## [10.0.0-35](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-34...v10.0.0-35) (2025-09-09) + + +### Features + +* add task prerequisites ([d5c1a51](https://github.com/b0ink/doubtfire-deploy/commit/d5c1a51dc049b025ae85b2ef6513630a197eabee)) +* cross out prerequisite tasks that have been submitted ([7e1a7db](https://github.com/b0ink/doubtfire-deploy/commit/7e1a7dbd3351dbcc8230f115554d6afdfaca0f70)) +* show list of prerequisites in task dashboard ([111f60a](https://github.com/b0ink/doubtfire-deploy/commit/111f60a4272abcf683c50b711bd43a1f772153ec)) + + +### Bug Fixes + +* typo ([e0c867f](https://github.com/b0ink/doubtfire-deploy/commit/e0c867fc7f24301d414ed584b6859e09d95c652c)) + +## [10.0.0-34](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-33...v10.0.0-34) (2025-09-08) + + +### Features + +* task assessment counts csv ([c2c6002](https://github.com/b0ink/doubtfire-deploy/commit/c2c6002cef6e5a75f722c964bf2843cf662380f4)) + + +### Bug Fixes + +* allow scrolling in edit profile form dialog ([ee2b908](https://github.com/b0ink/doubtfire-deploy/commit/ee2b9085a931df551408cd12dbc8187c04d088fc)) + +## [10.0.0-33](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-32...v10.0.0-33) (2025-09-04) + +## [10.0.0-32](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-31...v10.0.0-32) (2025-09-02) + +## [10.0.0-31](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-30...v10.0.0-31) (2025-08-27) + + +### Bug Fixes + +* use new checked_in comment type ([3033c6c](https://github.com/b0ink/doubtfire-deploy/commit/3033c6ca3c27ad4fc0a7ce4bda3ac44df09516e3)) + +## [10.0.0-30](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-29...v10.0.0-30) (2025-08-27) + +## [10.0.0-29](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-28...v10.0.0-29) (2025-08-27) + +## [10.0.0-28](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-27...v10.0.0-28) (2025-08-27) + +## [10.0.0-27](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-26...v10.0.0-27) (2025-08-27) + + +### Features + +* add option for qr footer text ([9e9b9db](https://github.com/b0ink/doubtfire-deploy/commit/9e9b9dbfb13d7531cb5387060407e23c25212cca)) +* support viewing qr for selected student in tutor view ([1f7fa51](https://github.com/b0ink/doubtfire-deploy/commit/1f7fa51d65767b3186e6eda8970a408cf0e6c847)) + + +### Bug Fixes + +* add padding when edit profile form displayed as modal ([a3f3b97](https://github.com/b0ink/doubtfire-deploy/commit/a3f3b977251a206b268c369c370934ff69b574d3)) +* show student id ([d1eeefb](https://github.com/b0ink/doubtfire-deploy/commit/d1eeefbea53cb13385bef2b3ba6b04d2f606c391)) + +## [10.0.0-26](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-25...v10.0.0-26) (2025-08-27) + + +### Features + +* add attendance marked task comment ([1559e81](https://github.com/b0ink/doubtfire-deploy/commit/1559e8104c8c4bc137df4f46a0a5ed0e345260af)) +* add tutor discussion to unit dropdown ([90f4149](https://github.com/b0ink/doubtfire-deploy/commit/90f41493313d6a3ad9bdafdd4cd4865c80e94ca2)) +* redirect back to inbox if unit context exists ([b7f4ab9](https://github.com/b0ink/doubtfire-deploy/commit/b7f4ab9e7801fbb33ffc6b4e02bf6613e6d7a524)) + + +### Bug Fixes + +* enforce minimum height on task comments viewer ([a7588e6](https://github.com/b0ink/doubtfire-deploy/commit/a7588e6f007381c04a570650257cd6f2ff93e5ae)) +* set max width on main container ([d1e5ab1](https://github.com/b0ink/doubtfire-deploy/commit/d1e5ab1427352fcf1b0fdd920cb9838a4f8799a0)) + +## [10.0.0-25](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-24...v10.0.0-25) (2025-08-26) + + +### Bug Fixes + +* only clear draft comment after successfully sending message ([2556355](https://github.com/b0ink/doubtfire-deploy/commit/2556355b0c3e1770fab021ed7d46e462882025b3)) + +## [10.0.0-24](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-23...v10.0.0-24) (2025-08-21) + +## [10.0.0-23](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-22...v10.0.0-23) (2025-08-14) + +## [10.0.0-22](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-21...v10.0.0-22) (2025-08-14) + + +### Features + +* download tasks awaiting feedback csv ([4a94373](https://github.com/b0ink/doubtfire-deploy/commit/4a943736689e41c405a831ca88a1303fb7c00385)) + + +### Bug Fixes + +* add return statement ([b8779e7](https://github.com/b0ink/doubtfire-deploy/commit/b8779e70d4decdc837caa8c84e8e8e2dfd3faf7f)) +* show full progress when sidekiq job is complete ([6a60d94](https://github.com/b0ink/doubtfire-deploy/commit/6a60d94b896d173a5008badd1b45bc7f45eee808)) + +## [10.0.0-21](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-20...v10.0.0-21) (2025-08-12) + + +### Bug Fixes + +* clear notification after fetching task comments ([c2d1536](https://github.com/b0ink/doubtfire-deploy/commit/c2d15367d9c53cb426dd12e73dc8d0b779a7f563)) + +## [10.0.0-20](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-19...v10.0.0-20) (2025-08-11) + +## [10.0.0-19](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-18...v10.0.0-19) (2025-08-07) + + +### Features + +* mark as discussed button in mobile tutor discussion ([9e62214](https://github.com/b0ink/doubtfire-deploy/commit/9e62214df772355048f4c7c7ffc13f3181f746e2)) + +## [10.0.0-18](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-17...v10.0.0-18) (2025-07-31) + + +### Bug Fixes + +* ensure no progress returns 0 ([9cb1f1a](https://github.com/b0ink/doubtfire-deploy/commit/9cb1f1ab770ac798ec8ecc555ceb73024bc98649)) + +## [10.0.0-17](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-16...v10.0.0-17) (2025-07-31) + + +### Features + +* return task to not started status ([bce1483](https://github.com/b0ink/doubtfire-deploy/commit/bce1483296064bafd44bc538f83731809d816a05)) + + +### Bug Fixes + +* check if project task stats exist ([e59af80](https://github.com/b0ink/doubtfire-deploy/commit/e59af803f8440338b0210b6a437537372f5dac5b)) +* ensure new comments are fetched for selected project only ([3b0e387](https://github.com/b0ink/doubtfire-deploy/commit/3b0e3877e05f162143fc78065cee9a191d0755f4)) +* ensure whitespace is trimmed ([fe687df](https://github.com/b0ink/doubtfire-deploy/commit/fe687df8b035ef851b9d147e01f575187f428a8c)) +* prevent additional inbox queries ([0d35f7f](https://github.com/b0ink/doubtfire-deploy/commit/0d35f7f4ef2e87dd078edf20e509c8f6efc5c216)) + +## [10.0.0-16](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-15...v10.0.0-16) (2025-07-29) + +## [10.0.0-15](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-14...v10.0.0-15) (2025-07-29) + + +### Bug Fixes + +* correctly load start page ([e297f26](https://github.com/b0ink/doubtfire-deploy/commit/e297f261e3df19faf11be9fde6515ce75434c320)) +* map correct variables ([b180799](https://github.com/b0ink/doubtfire-deploy/commit/b180799efd716d802cf83ce08b6df0639d9055b6)) +* prevent report button from expanding accordion ([e715415](https://github.com/b0ink/doubtfire-deploy/commit/e7154157ff1b88817141bae5b1b3de9fd37171f0)) + +## [10.0.0-14](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-13...v10.0.0-14) (2025-07-28) + + +### Features + +* portfolio zip downloading via sidekiq ([9000830](https://github.com/b0ink/doubtfire-deploy/commit/9000830e5e98bc0b921d618c034471eeddf996b4)) +* show list of active sidekiq jobs ([aa85665](https://github.com/b0ink/doubtfire-deploy/commit/aa85665670a23fea556c6420f139e7e7853d16ba)) +* show maintenance ui when api fails ([29bb95f](https://github.com/b0ink/doubtfire-deploy/commit/29bb95f5974dc8f258b204957a212a8399ad2d6e)) +* sidekiq progress modal component ([b9691e7](https://github.com/b0ink/doubtfire-deploy/commit/b9691e793204e84fae323610a7b555b15e065514)) + + +### Bug Fixes + +* fallback to task definition due date ([bef0a9c](https://github.com/b0ink/doubtfire-deploy/commit/bef0a9cbfefc58407f851d3ca73b90af6b81151f)) + +## [10.0.0-13](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-12...v10.0.0-13) (2025-07-16) + + +### Bug Fixes + +* display task-date-slider only when task exists ([c886034](https://github.com/macite/doubtfire-deploy/commit/c886034d4bf69851f4b06599a45bd1b135c3fff2)) + +## [10.0.0-12](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-11...v10.0.0-12) (2025-07-15) + + +### Bug Fixes + +* exclude jplag route from ngsw cache ([69b55bb](https://github.com/macite/doubtfire-deploy/commit/69b55bb85d8583b6935e08c91aad63e98e6ce887)) + +## [10.0.0-11](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-10...v10.0.0-11) (2025-07-15) + +## [10.0.0-10](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-9...v10.0.0-10) (2025-07-15) + +## [10.0.0-9](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-8...v10.0.0-9) (2025-07-15) + +## [10.0.0-8](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-7...v10.0.0-8) (2025-07-15) + +## [10.0.0-7](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-6...v10.0.0-7) (2025-07-14) + + +### Features + +* add icon to discussed in class update ([c11cec0](https://github.com/macite/doubtfire-deploy/commit/c11cec02ece3b6bf7c2e36998ee2fa2a3572bc58)) +* add jplag report download button to student submission tutor teacher footer view ([2ec1b06](https://github.com/macite/doubtfire-deploy/commit/2ec1b06b5330c5e142cc3fc01c49c2aded5411cb)) +* add tutor discussion qr scanning ([e549c4e](https://github.com/macite/doubtfire-deploy/commit/e549c4e0ac9377bd864c81122cffce004681c845)) +* auto send dicussed in class comment ([fbf90c7](https://github.com/macite/doubtfire-deploy/commit/fbf90c7fdfa440f565e2c8abae4ae62bc1fe70eb)) +* **comments:** enhanced drafting for messages using localStorage ([f331734](https://github.com/macite/doubtfire-deploy/commit/f33173409f0804da4de24e1e6ec53971896b28e9)) +* **comments:** enhanced drafting for messages using localStorage ([b6f6831](https://github.com/macite/doubtfire-deploy/commit/b6f683175db6ab9549b8b4481ab54bb89700016a)) +* edit staff note ([b2d8ba4](https://github.com/macite/doubtfire-deploy/commit/b2d8ba41b1dc467a03728d5df4ede6ac6fb3c9a1)) +* fetch new comments on task switching and status updates ([1b7da69](https://github.com/macite/doubtfire-deploy/commit/1b7da692423acaf53b96229b665b971360bacc89)) +* force scanner to use back camera, enhance ux ([e5799b1](https://github.com/macite/doubtfire-deploy/commit/e5799b18ec0603123b6a99b3733919d2611b4fbd)) +* highlight selected task ([25b361f](https://github.com/macite/doubtfire-deploy/commit/25b361f699ad54e45c32167ccae230635a6b2758)) +* indicate reply has been deleted ([c3e288a](https://github.com/macite/doubtfire-deploy/commit/c3e288ae95e2fa5fd43bdf3922e81501f26e1baf)) +* init qr tutor marking state ([41d1d61](https://github.com/macite/doubtfire-deploy/commit/41d1d61a417573e33c4344898ae6d7562c459004)) +* init reply to button ([100a533](https://github.com/macite/doubtfire-deploy/commit/100a5335aa7f37f4477b9d9b8f43806ca32c640b)) +* init staff notes ([c7eed99](https://github.com/macite/doubtfire-deploy/commit/c7eed9903bcc4463f4d0b52889e0d3d9045b03ba)) +* jplag report download button in task explorer view ([16670a2](https://github.com/macite/doubtfire-deploy/commit/16670a27d5dc544ae828da85cda48358cab4d75e)) +* link note that is being replied to ([27726b3](https://github.com/macite/doubtfire-deploy/commit/27726b3f1368031c24bf069bde4f930dd02c1e80)) +* load jplag report viewer into iframe ([1360438](https://github.com/macite/doubtfire-deploy/commit/13604383b403dbf82b013786127a72fab08ac895)) +* localized date time pipe ([5cf752b](https://github.com/macite/doubtfire-deploy/commit/5cf752baf1b9de6105ea2a951ec75818ce1e0cfc)) +* mark task as discussed ([a54f94f](https://github.com/macite/doubtfire-deploy/commit/a54f94f045b4280d0f13304a6b5728b62fc4107e)) +* message tooltip timestamps ([2d79007](https://github.com/macite/doubtfire-deploy/commit/2d79007c033d56218326f55dd8d6821e17fec74f)) +* native jplag report viewer state ([8f6bc6a](https://github.com/macite/doubtfire-deploy/commit/8f6bc6ae5b80502b5d81b65bab2be3aaa56ce42f)) +* qr code generation for student projects ([6f8b94f](https://github.com/macite/doubtfire-deploy/commit/6f8b94f7c0b48d292dfe28871ff7ae7fda86b2b9)) +* redirect back to home if exiting the scanner ([71f09ae](https://github.com/macite/doubtfire-deploy/commit/71f09ae77da6f0a2f5ed135071c92c110940c2f5)) +* reply to ui ([40078df](https://github.com/macite/doubtfire-deploy/commit/40078df477bd300c9b8897976d10658fb91a6d04)) +* show number of notes project has ([f3d4c4c](https://github.com/macite/doubtfire-deploy/commit/f3d4c4c00128ca00dec18ea9950c01df25b75b61)) +* staff note deletion ([0ab1ebf](https://github.com/macite/doubtfire-deploy/commit/0ab1ebff3964d8665d9560bf3007a2d30109ee37)) +* switch to staff note tab view ([65f8c71](https://github.com/macite/doubtfire-deploy/commit/65f8c71bd37ef71481bd14f591af263470987a6e)) +* task and unit ilos ui ([1cef438](https://github.com/macite/doubtfire-deploy/commit/1cef438b458efcee4adce01cc81648d32bb97f35)) +* view filtered tasks only button ([a4e422d](https://github.com/macite/doubtfire-deploy/commit/a4e422dcf3dfa329b83cd7e3d521fc3665c9c45f)) +* view staff notes in portfolio assessment ([020ab5b](https://github.com/macite/doubtfire-deploy/commit/020ab5b9a98a401835e41bee7abc3dee70978c07)) + + +### Bug Fixes + +* allow oversized images to be scrollable ([8ff67d2](https://github.com/macite/doubtfire-deploy/commit/8ff67d2f8e483813bc3af0dc2429b58fe16f8f2b)) +* avoid fetching twice if no comments are cached yet ([d219d49](https://github.com/macite/doubtfire-deploy/commit/d219d49ca6457119084d4c3d2cb39343dece5aa0)) +* decode url from qr code ([31822ab](https://github.com/macite/doubtfire-deploy/commit/31822abaa4c66e2dcbc3ab74c71fe0f6e9b5861d)) +* discussed context type ([d87e620](https://github.com/macite/doubtfire-deploy/commit/d87e620ab54aa75f03d8295f0319798214ad39f0)) +* display load more button only if there are more tasks ([84d5bca](https://github.com/macite/doubtfire-deploy/commit/84d5bcaa4f6329ed34f30a58d88e18fce9c3a76d)) +* enable unit name text wrapping ([5f779b8](https://github.com/macite/doubtfire-deploy/commit/5f779b8cb626ada2e8b6488812424813cc5e9913)) +* ensure jplag iframe extends to full height ([7ae6466](https://github.com/macite/doubtfire-deploy/commit/7ae6466e6586ceaf58edec8a741c9e2f8a737c0c)) +* ensure scanner doesn't break on ios ([a0b010e](https://github.com/macite/doubtfire-deploy/commit/a0b010ef31161b6cf2ab1038deb82c199ffb9ecb)) +* improve task similarity notice ui ([ba26841](https://github.com/macite/doubtfire-deploy/commit/ba2684192c2a8a139237affc4c0702af901f1808)) +* match comments-modals's original max width ([7edb445](https://github.com/macite/doubtfire-deploy/commit/7edb445d7bc5f61daba1b47a3a36b633b551267e)) +* merge conflict ([e599fe3](https://github.com/macite/doubtfire-deploy/commit/e599fe35ec338cfd7f5ffc419a3379d3f3160312)) +* show edit icon for authors only ([a83a875](https://github.com/macite/doubtfire-deploy/commit/a83a875f25efbe9297fe76d773ef4ff55456bcf8)) +* support markdown ([3ac10f6](https://github.com/macite/doubtfire-deploy/commit/3ac10f6cab39dab42ce19f61029488d220786703)) +* **task-comment-composer:** deleting the key when text is empty ([6ef91e0](https://github.com/macite/doubtfire-deploy/commit/6ef91e0ddb119e03dbaf2b6e53e450e5bcc58b8b)) +* update discussion route ([b5c35d9](https://github.com/macite/doubtfire-deploy/commit/b5c35d9cb0be11a6c6cbd49d9e6aee37bb5b83cd)) +* welcome page redirect issues ([14ad26e](https://github.com/macite/doubtfire-deploy/commit/14ad26e8ed4acf6f77043447a2691360fd62ce51)) + +## [10.0.0-6](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-5...v10.0.0-6) (2025-06-13) + + +### Features + +* add spec con and flexible dates ([a874cff](https://github.com/macite/doubtfire-deploy/commit/a874cff846e788a1820da7e19899ecb20a113888)) + + +### Bug Fixes + +* only get task feedback templates if staff ([8341b93](https://github.com/macite/doubtfire-deploy/commit/8341b933487ccd451a15cb8f7ec6afc1695cb121)) +* remove unnecessary safe pipe ([c92242a](https://github.com/macite/doubtfire-deploy/commit/c92242ad9afb0a934d4e8fb00afee0c69782c625)) + +## [10.0.0-5](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-4...v10.0.0-5) (2025-05-30) + + +### Bug Fixes + +* correct broken transition hooks ([d237eda](https://github.com/macite/doubtfire-deploy/commit/d237eda82dd989fc1b69d6e4236932050bc5b1a4)) +* delay authorisation code until after authentication ([34410d4](https://github.com/macite/doubtfire-deploy/commit/34410d4afdf5bd73d9c244a6f40c7fb78b714e63)) +* ensure transition in student pages update pdf view ([68a2f38](https://github.com/macite/doubtfire-deploy/commit/68a2f38167c792974aafd907f04fcf9e8b5bf091)) +* simplify setting of auto redirect on login ([60dbceb](https://github.com/macite/doubtfire-deploy/commit/60dbceb2a104894b4eff157c038446796bf01708)) + +## [10.0.0-4](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-3...v10.0.0-4) (2025-04-15) + + +### Bug Fixes + +* ensure sign in waits for global load ([fb6e61f](https://github.com/macite/doubtfire-deploy/commit/fb6e61f874797cd48e77f2a8d0a32f345f5b785b)) + +## [10.0.0-3](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-2...v10.0.0-3) (2025-04-10) + + +### Bug Fixes + +* correct auth callback ([2e087d2](https://github.com/macite/doubtfire-deploy/commit/2e087d267c8bfde633550823aed460379a643ad9)) + +## [10.0.0-2](https://github.com/macite/doubtfire-deploy/compare/v10.0.0-1...v10.0.0-2) (2025-04-10) + + +### Bug Fixes + +* correct handling of errors on auth ([622768a](https://github.com/macite/doubtfire-deploy/commit/622768a06112910d5ba79061689fc0ba486982a5)) + +## [10.0.0-1](https://github.com/macite/doubtfire-deploy/compare/v8.0.37...v10.0.0-1) (2025-04-10) + + +### Features + +* add comment text to comment area ([5c45415](https://github.com/macite/doubtfire-deploy/commit/5c45415eafb38e221963781e4575480294d74e09)) +* add connected learning outcomes ([9532d9f](https://github.com/macite/doubtfire-deploy/commit/9532d9ffe620d67d7bc83137d59e0a91ecf8a73a)) +* add editor for task feedback templates ([3da7a4b](https://github.com/macite/doubtfire-deploy/commit/3da7a4b54a5892ea99cd365ae439677b0f52ed6f)) +* add feedback template picker to comment composer ([9acc365](https://github.com/macite/doubtfire-deploy/commit/9acc36502dc3fd2365817f73ccc742dd3947e293)) +* add field to connect outcomes ([db2d2bc](https://github.com/macite/doubtfire-deploy/commit/db2d2bc32b19165bac8ff6ba0282a16adffbb815)) +* add glo editor ([4efe876](https://github.com/macite/doubtfire-deploy/commit/4efe87694a426c4b6a55ef943576fe47498166e5)) +* add greeting and summary chip ([ed68317](https://github.com/macite/doubtfire-deploy/commit/ed683174ab7b330a48b2aeacdd65012396357479)) +* add option for institution logo ([5141529](https://github.com/macite/doubtfire-deploy/commit/5141529b1ed37f8ca254e89e1b91edac3139f166)) +* add startpage property to auto scroll to on pdf render ([90830cd](https://github.com/macite/doubtfire-deploy/commit/90830cdba73bcfe564362015b5abaf2c40810f5f)) +* combine outcome and template editor ([c12536b](https://github.com/macite/doubtfire-deploy/commit/c12536bc4375b1ae5f19d4e54d0783b6948921eb)) +* edit feedback chips ([04f8dce](https://github.com/macite/doubtfire-deploy/commit/04f8dce30f79d86637abd6db2aa9fa3aa14d1de2)) +* **feedback-template:** add hierarchical sorting for feedback templates ([8db1844](https://github.com/macite/doubtfire-deploy/commit/8db1844402d080902a9d3938ecc04dd7a2f0340f)) +* **feedback-template:** improve sorting logic for feedback templates ([d3f156a](https://github.com/macite/doubtfire-deploy/commit/d3f156a640e6a3da99c147c4c2303a1af3050f8f)) +* **feedback-template:** merge upstream changes ([0fb1d8a](https://github.com/macite/doubtfire-deploy/commit/0fb1d8abfa3264befddd97e1ce0832359866919d)) +* fetch feedback chips when selecting task in unit editor ([9caeda4](https://github.com/macite/doubtfire-deploy/commit/9caeda4e71946ddb7907027ebf7a54397f11606f)) +* init pdf viewer on page 2 for student submissions ([45cc89e](https://github.com/macite/doubtfire-deploy/commit/45cc89e18cff8fcde66480448eea178940d316a2)) +* make template editor reusable across contexts ([a42f177](https://github.com/macite/doubtfire-deploy/commit/a42f177f61b3f7166edf3b9c93dfd2dcd3949df7)) +* modify fields and operate on learning outcomes ([65ffc4f](https://github.com/macite/doubtfire-deploy/commit/65ffc4f8d61a9d0b2cc7c5f8d13db932436fc4f5)) +* persistent pdf zoom level ([1348da2](https://github.com/macite/doubtfire-deploy/commit/1348da2d345b080002a62a24d717fac15c4b0a92)) +* rebuild auth with refresh token ([5d3a36e](https://github.com/macite/doubtfire-deploy/commit/5d3a36e8f16e8993c5607241112c490361a31c97)) +* show chips on picker ([e54216f](https://github.com/macite/doubtfire-deploy/commit/e54216f8472b67cf9f2ff69c9bcb3355efa90081)) +* suggest task status according to feedback ([95796da](https://github.com/macite/doubtfire-deploy/commit/95796da4e7855bcd76023754d95cec8d033668fc)) + + +### Bug Fixes + +* adjust ui for nested csv modal ([d7fac6f](https://github.com/macite/doubtfire-deploy/commit/d7fac6f0fb23f060373fd4c40f5e82b960098c77)) +* check difference before updating linked outcomes ([aa0bc76](https://github.com/macite/doubtfire-deploy/commit/aa0bc76d32656dc14d28ebca520e4f90d6d9434e)) +* check for unit context for template csv name ([6ecec84](https://github.com/macite/doubtfire-deploy/commit/6ecec8483222304161f9cda87a8bdf3ecd774bcb)) +* comment console logs ([e86162d](https://github.com/macite/doubtfire-deploy/commit/e86162d1592d8418bab3c889b1d0bbfe3662b86d)) +* correct a typo in /edit_profile ([4b7901f](https://github.com/macite/doubtfire-deploy/commit/4b7901fd03d9652230aecb52791313f052d7b53d)) +* correct string manipulation for task period formatting ([aa06cbf](https://github.com/macite/doubtfire-deploy/commit/aa06cbf3a08efa02f508062d47c127289fc8c6fa)) +* display feedback picker chips in color ([6ae0771](https://github.com/macite/doubtfire-deploy/commit/6ae077149d16e5af538d432a9ce2db974298b549)) +* display nested feedback groups in picker ([db93b18](https://github.com/macite/doubtfire-deploy/commit/db93b187cfe6e197a3b6243445809ec6d767d4bd)) +* display task status in coloured chip in feedback editor ([73986e8](https://github.com/macite/doubtfire-deploy/commit/73986e89839603b19f643404e5a48964ac9a3c1b)) +* exclude greeting and summary from selected ([1978e54](https://github.com/macite/doubtfire-deploy/commit/1978e5410f6aa9314252ae3cf922917033f551f0)) +* feedback picker search ([3a5e02e](https://github.com/macite/doubtfire-deploy/commit/3a5e02e2f7864b9e1ea4f8d49ce69d23addbcc5a)) +* **feedback-template-editor:** add missing operator ([a1f220c](https://github.com/macite/doubtfire-deploy/commit/a1f220c9f5462a2b91035eb936f3ff25b7d4cd67)) +* **feedback-template-editor:** improve feedback template sorting logic ([bd48c40](https://github.com/macite/doubtfire-deploy/commit/bd48c40c4c3b0a3d67d41373b624ed8b3b754f4a)) +* **feedback-template:** ensure sorting defaults are applied ([96f7555](https://github.com/macite/doubtfire-deploy/commit/96f7555f9dfcf4c62ee3dd54b9e9e74087bec47a)) +* focus on composer input after selecting chip ([95afdff](https://github.com/macite/doubtfire-deploy/commit/95afdff12aac914bb8af8727f8b8d960bc3b072c)) +* hide feedback group comment text ([55a6625](https://github.com/macite/doubtfire-deploy/commit/55a662584c4b8b6123335bcbc5149a9f0f0701d8)) +* hide picker on task change ([198b7f9](https://github.com/macite/doubtfire-deploy/commit/198b7f9d0ccad631059ed5e1ad5487604582074b)) +* hide summary instead of comment text for groups ([7644cba](https://github.com/macite/doubtfire-deploy/commit/7644cba92f92f5c261501c1907f7f5418538e3a7)) +* hide template editor on outcome switch ([a3706e9](https://github.com/macite/doubtfire-deploy/commit/a3706e9394b78edf9ec15030246c98acca9d3852)) +* lock ng2-pdf-viewer to 10.2.2 ([2cf6215](https://github.com/macite/doubtfire-deploy/commit/2cf62152524ec728c73aaa23f678bbce9ae6b4d1)) +* only get feedback chips if staff ([7f4381e](https://github.com/macite/doubtfire-deploy/commit/7f4381e1179400642821068d1acdba346a2969a2)) +* organise outcome and feedback csv functionality ([641f1d9](https://github.com/macite/doubtfire-deploy/commit/641f1d9f75177d48b3911c300e23c901e0a603e1)) +* prevent saving empty items ([0eed547](https://github.com/macite/doubtfire-deploy/commit/0eed5477940db511cee09bbdb7ccb0adde57cbbf)) +* refine feedback editor ([f410cfe](https://github.com/macite/doubtfire-deploy/commit/f410cfe47b0c242f1a164c6345bc4d29f5659f6a)) +* refresh context when changing task defs ([c078bcf](https://github.com/macite/doubtfire-deploy/commit/c078bcf40198c5495d4c94354fab411d3e0ee934)) +* remove duplicate alert ([955d0a1](https://github.com/macite/doubtfire-deploy/commit/955d0a17ae23be77954145ba189ac8bb0aa90da0)) +* remove glo outcome specific csv buttons ([579c491](https://github.com/macite/doubtfire-deploy/commit/579c49170808a6fcca1bfd67f0923f0339255463)) +* remove selected outcomes from dropdown ([5494384](https://github.com/macite/doubtfire-deploy/commit/5494384f1a4becf462dd031e89fae2734ed46e55)) +* reply to position and wrapping ([e065c46](https://github.com/macite/doubtfire-deploy/commit/e065c46c3fe6689a7b295a3f91a576eabc11f7bd)) +* reset template table for new outcome ([7585c1c](https://github.com/macite/doubtfire-deploy/commit/7585c1c60ca8fe168084ec3d857aec4856bfb0db)) +* save connected outcomes ([eb3cf6d](https://github.com/macite/doubtfire-deploy/commit/eb3cf6daf99b893642336efb48ed58bc9c8b8207)) +* save linked outcomes upon selection ([07f103d](https://github.com/macite/doubtfire-deploy/commit/07f103de46defa2a78f5d7c43030e67255c0d5fe)) +* save to proper cache and clean up ([80edff2](https://github.com/macite/doubtfire-deploy/commit/80edff2ef04137b3d38ccdd252788cfb40f458f0)) +* show description for connected outcome selection ([0f2c164](https://github.com/macite/doubtfire-deploy/commit/0f2c164579491298b81849cc110301229f2ca5af)) +* show picker above composer and below comments ([ef524f1](https://github.com/macite/doubtfire-deploy/commit/ef524f1b048b3bfe1781307a34e1a5fe364943a4)) +* show proper selected outcome or template ([0ac3881](https://github.com/macite/doubtfire-deploy/commit/0ac3881e7f6d0f5b7ddeb85e5e8f9e6835c5dba6)) +* support hot reloading on windows ([247330e](https://github.com/macite/doubtfire-deploy/commit/247330e46d74186519dbcbbef8378b508eaca83f)) +* support windows build ([3594528](https://github.com/macite/doubtfire-deploy/commit/35945288c73052afd28209a7381335af2b14ba10)) +* template editor not showing if new ([6cfe379](https://github.com/macite/doubtfire-deploy/commit/6cfe37999fa7f484e1b89f4dbe657b99907adae1)) +* tlo csv url ([73588d8](https://github.com/macite/doubtfire-deploy/commit/73588d886118861bbd3e5ae380cddc7baa532dbb)) +* update packages ([e5a57f8](https://github.com/macite/doubtfire-deploy/commit/e5a57f8ba3669345a272b308b0c892fdab4843ef)) +* upon save update entity in frontend ([a128744](https://github.com/macite/doubtfire-deploy/commit/a1287449b945295ced60e86a21bcaab67ed0f9bd)) +* use icon instead of color for template task status ([11a3993](https://github.com/macite/doubtfire-deploy/commit/11a399324ee64af901f44f28de3526cbd7650bac)) +* use task status color for recommended button ([174cde0](https://github.com/macite/doubtfire-deploy/commit/174cde0022d0c728d2c6408d40129d6c343aa91d)) + +### [8.0.37](https://github.com/macite/doubtfire-deploy/compare/v8.0.36...v8.0.37) (2025-03-10) + + +### Bug Fixes + +* ensure overseer download get resources zip ([a1e4d71](https://github.com/macite/doubtfire-deploy/commit/a1e4d71b34733bc53cd2cfa63ee1e70f8f43386f)) + +### [8.0.36](https://github.com/macite/doubtfire-deploy/compare/v8.0.35...v8.0.36) (2025-03-07) + + +### Bug Fixes + +* overseer image admin in unit and task ([72c89b3](https://github.com/macite/doubtfire-deploy/commit/72c89b30cca426d56c7efbbac34e00fd734fe714)) + +### [8.0.35](https://github.com/macite/doubtfire-deploy/compare/v8.0.34...v8.0.35) (2025-02-28) + + +### Bug Fixes + +* correct ability to edit teaching periods ([ce37bf2](https://github.com/macite/doubtfire-deploy/commit/ce37bf27689744a6f43be46912be0d14e2cdbc6b)) +* ensure an old grade is present in portfolio assessment ([7daacd1](https://github.com/macite/doubtfire-deploy/commit/7daacd1bf0af050aeb6db503d963e574f68b9a94)) +* ensure overseer images can be edited ([3479b7a](https://github.com/macite/doubtfire-deploy/commit/3479b7af589b9ba986ddbb7dc8a84fd0be3e66e6)) + +### [8.0.34](https://github.com/macite/doubtfire-deploy/compare/v8.0.33...v8.0.34) (2025-02-12) + + +### Bug Fixes + +* enhance rollover messages ([48348c8](https://github.com/macite/doubtfire-deploy/commit/48348c8e6a7ffdb4186fe3e6d27fe860076922e1)) + +### [8.0.33](https://github.com/macite/doubtfire-deploy/compare/v8.0.32...v8.0.33) (2025-01-29) + + +### Bug Fixes + +* nginx conf redirect for spa ([95c0ca9](https://github.com/macite/doubtfire-deploy/commit/95c0ca9384e5a0fe7e522f61146b711b706712c1)) + +### [8.0.32](https://github.com/macite/doubtfire-deploy/compare/v8.0.31...v8.0.32) (2025-01-29) + + +### Bug Fixes + +* correct issue fetching user from cookie ([0d63775](https://github.com/macite/doubtfire-deploy/commit/0d63775339dcbb648d7c8702b1c3428b8622a704)) + +### [8.0.31](https://github.com/macite/doubtfire-deploy/compare/v8.0.30...v8.0.31) (2025-01-28) + + +### Bug Fixes + +* ensure test attempt work for staff students ([06bfa71](https://github.com/macite/doubtfire-deploy/commit/06bfa714d0b54938231004a29ae11e68fe515d80)) +* serve index.html for unknown paths ([d07ad26](https://github.com/macite/doubtfire-deploy/commit/d07ad26bd7e7bd8ba7c7877a1208a8f82958c72b)) + +### [8.0.30](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.29...v8.0.30) (2025-01-22) + + +### Features + +* add ability to collect d2l org and grade object ids ([93fd614](https://github.com/doubtfire-lms/doubtfire-deploy/commit/93fd6144c798fd302204728a6c2dd43f74d7bf91)) +* add ability to trigger d2l grade transfer ([fd0cc07](https://github.com/doubtfire-lms/doubtfire-deploy/commit/fd0cc0737682e9aa02af14f858c8a5f5f27f22e7)) +* add success page for oauth callback ([921406e](https://github.com/doubtfire-lms/doubtfire-deploy/commit/921406ed595c7a74cb750bc87d49fac0337bdb8a)) +* check if d2l results available ([2460c88](https://github.com/doubtfire-lms/doubtfire-deploy/commit/2460c88af08740f8626ed71d8851a75af095a03d)) +* d2l integration checks settings ([0a61df5](https://github.com/doubtfire-lms/doubtfire-deploy/commit/0a61df53c9fc187b7462e8564a19641ac1693cf0)) +* switch to html5 mode ([9d017fb](https://github.com/doubtfire-lms/doubtfire-deploy/commit/9d017fbfaa1d5bae7f43da37ec7ae43e1dfafa8f)) + + +### Bug Fixes + +* ensure standard error propagate to the ui ([fd056db](https://github.com/doubtfire-lms/doubtfire-deploy/commit/fd056db47631087d5ef29223bd3dc9037c4b10dd)) +* report better errors during file downloads ([cf87d68](https://github.com/doubtfire-lms/doubtfire-deploy/commit/cf87d68ea3a5433a073ae6db413f8c1f825ada80)) + +### [8.0.29](https://github.com/macite/doubtfire-deploy/compare/v8.0.28...v8.0.29) (2024-10-25) + + +### Features + +* add support for the view language ([151ca04](https://github.com/macite/doubtfire-deploy/commit/151ca04ca8da9059890d7846293bf34ae67f05c5)) + + +### Bug Fixes + +* correct task scroll into view ([7984b39](https://github.com/macite/doubtfire-deploy/commit/7984b393752381e0a219dbbdafc0e7b44c3fcdb3)) + +### [8.0.27](https://github.com/macite/doubtfire-deploy/compare/v8.0.26...v8.0.27) (2024-08-09) + + +### Bug Fixes + +* encode . in the username in scorm player ([1ec1754](https://github.com/macite/doubtfire-deploy/commit/1ec175419ab3ef80f22ac8a6384f6ed40a17c217)) + +### [8.0.26](https://github.com/macite/doubtfire-deploy/compare/v8.0.25...v8.0.26) (2024-08-09) + + +### Bug Fixes + +* register service names in state resolve functions ([64e41f4](https://github.com/macite/doubtfire-deploy/commit/64e41f4aedcf519a2786d7fe4929900f86731896)) + +### [8.0.25](https://github.com/macite/doubtfire-deploy/compare/v8.0.24...v8.0.25) (2024-08-09) + + +### Bug Fixes + +* adjust shortcuts and unregister on inbox destroy ([8a2ce3b](https://github.com/macite/doubtfire-deploy/commit/8a2ce3bfe32d99be1bc0667ca1aba55d36f987d2)) +* switch to control shift ([a0c1185](https://github.com/macite/doubtfire-deploy/commit/a0c1185bf4af3acb8f58c97cc27021c952861603)) + +### [8.0.24](https://github.com/macite/doubtfire-deploy/compare/v8.0.23...v8.0.24) (2024-08-09) + + +### Features + +* add ability to preview scorm test ([7ffbea9](https://github.com/macite/doubtfire-deploy/commit/7ffbea9f56c393d44571c18f30735e090701b554)) +* add new Numbas Feature ([6f1ac4e](https://github.com/macite/doubtfire-deploy/commit/6f1ac4e4c1a78115c426838bce350bce286e44f0)) +* add new Numbas Feature ([8eba913](https://github.com/macite/doubtfire-deploy/commit/8eba913ec4462e1c252a8a698b4b6de67c4ec25f)) +* add numbas component ([7c1734b](https://github.com/macite/doubtfire-deploy/commit/7c1734b137ac369b3b605b38749c845df38b9a78)) +* add Numbas config options to task def service keys ([ff28e48](https://github.com/macite/doubtfire-deploy/commit/ff28e4802b86dc22be339cc196ef82ade67934f7)) +* add Numbas test attempt model ([097df79](https://github.com/macite/doubtfire-deploy/commit/097df7960d34a8c905ee495b8c6c8b8843e43b36)) +* add Numbas test section on ready for feedback ([e61295c](https://github.com/macite/doubtfire-deploy/commit/e61295c50006dbc89cfc0639bb3c68a09a3cda9d)) +* add Numbas test upload section and reorder editor sections ([edbd536](https://github.com/macite/doubtfire-deploy/commit/edbd536e73ace8b6b4cced1481c809fd36524dce)) +* add Numbas upload component and related functions to task-definition model ([4ecaee8](https://github.com/macite/doubtfire-deploy/commit/4ecaee8ad1c0caed9a5d848066a173000989f79b)) +* add test attempt service ([a576f48](https://github.com/macite/doubtfire-deploy/commit/a576f484bc434728eab9632c022bccf1ed26cb01)) +* add test attempt service and minor numbas related changes ([0652b56](https://github.com/macite/doubtfire-deploy/commit/0652b56f69eb850c2dfb43be54d07beb4c4eb469)) +* added numbas-lms service code ([471d344](https://github.com/macite/doubtfire-deploy/commit/471d34486f2582e95aac84469187f087277cc079)) +* allow changing scorm review config and add minor UI changes ([fc023af](https://github.com/macite/doubtfire-deploy/commit/fc023af462656e3557e2970f211fa4d59ee1e3d5)) +* change Numbas time delay config to enable incremental delays ([0afa719](https://github.com/macite/doubtfire-deploy/commit/0afa7197293c90a154c1716db91ecadae3677d53)) +* disable attempt button if passed and add button to review latest attempt in card ([703563c](https://github.com/macite/doubtfire-deploy/commit/703563c86253c60ad30d451ee2d8e0fa7ebbfabb)) +* display numbas task comments ([48a31da](https://github.com/macite/doubtfire-deploy/commit/48a31da1442f1e14f497c614053d9002c9f2631b)) +* enable reviewing, passing, deleting test attempts and add test attempt model and service ([561b924](https://github.com/macite/doubtfire-deploy/commit/561b9241c2f44fd69d3f09c656a025f514bbaf3a)) +* enable students to request extra scorm attempt ([d904ffd](https://github.com/macite/doubtfire-deploy/commit/d904ffd6fd674f6e61894d517f5aa147d1db6d29)) +* get unique token for scorm asset retrieval ([8fe2f9e](https://github.com/macite/doubtfire-deploy/commit/8fe2f9e9ca60c02e55c24d0f2bb3eb6dbea8217c)) +* implement numbas test data upload in task definition service ([2c7dab5](https://github.com/macite/doubtfire-deploy/commit/2c7dab555fc9a226b980a8dae96f5738bf517b1b)) +* insert Numbas test rules options in the task editor ([7e52ad5](https://github.com/macite/doubtfire-deploy/commit/7e52ad5e5759291d7d61805070ec482eb49c90be)) +* numbas-test-numbas-service ([cee13b7](https://github.com/macite/doubtfire-deploy/commit/cee13b727b35f804fc16070885f0e57c422c9982)) +* prevent uploading files until scorm passed ([ec86e4e](https://github.com/macite/doubtfire-deploy/commit/ec86e4eca8e9c50ebdaf54c34c302da88dd44b31)) +* show banner based on scorm success status ([db16172](https://github.com/macite/doubtfire-deploy/commit/db161721fab1359694c44d8df7237cd01892938b)) +* show launch button on ready for feedback if Numbas test is enabled for the task ([17af5b7](https://github.com/macite/doubtfire-deploy/commit/17af5b7fe9e1fbc8e5f18e2fece6e029b017408c)) +* use confirmation modal when passing or deleting test attempts ([3fb25bb](https://github.com/macite/doubtfire-deploy/commit/3fb25bb373acab837a3ef787620dd654bfd6803f)) + + +### Bug Fixes + +* add accepted Numbas file types ([bcaa8af](https://github.com/macite/doubtfire-deploy/commit/bcaa8af150aaf68b5cf5fb07ad9cb72037212d5d)) +* add auth headers to scorm adapter xhr requests ([97e1ea1](https://github.com/macite/doubtfire-deploy/commit/97e1ea187b769a51ebb66b82d76f21193bb29386)) +* adjusted edit profile accidental change ([316abc7](https://github.com/macite/doubtfire-deploy/commit/316abc775eeba6ca846c7c742bc88bec61d05a5e)) +* change success status descriptions ([20da042](https://github.com/macite/doubtfire-deploy/commit/20da0423450fe3b9b8006660bf6f5e06670f520c)) +* delete comment as well as test attempt ([b6887e8](https://github.com/macite/doubtfire-deploy/commit/b6887e85b7a06b166519924dd682ef57650a4e32)) +* disable launch scorm test button if user is staff ([9bc48b0](https://github.com/macite/doubtfire-deploy/commit/9bc48b03905c0a839d78ea13be9817ca73ba54cf)) +* ensure counters are incremented after object creation ([2b1dcfc](https://github.com/macite/doubtfire-deploy/commit/2b1dcfc717eb770dd623c62ac99d8d961d1c3124)) +* ensure datamodel is updated on termination ([2ac487f](https://github.com/macite/doubtfire-deploy/commit/2ac487f13c3743f2b5b805521964bdcbca7cdc15)) +* ensure scorm frame loads when src is available ([6ae4295](https://github.com/macite/doubtfire-deploy/commit/6ae42954162996acf145cef211981153381ff49d)) +* hide config options if numbas test is disabled ([0b15b1c](https://github.com/macite/doubtfire-deploy/commit/0b15b1c38b8f09a30f53bb42dccd1971109bce01)) +* indicate task def has scorm data when zip is uploaded ([4b983ba](https://github.com/macite/doubtfire-deploy/commit/4b983bae1f522013f750b8c36d5e1a52624abbbc)) +* initialise SCORM API wrapper before iframe loads ([5d0606c](https://github.com/macite/doubtfire-deploy/commit/5d0606c56eaeb929d5873cae7038ce729581512c)) +* integrate Numbas services well with the existing system ([d47b8ed](https://github.com/macite/doubtfire-deploy/commit/d47b8edc745660801984346c4fa67d6bb371f4cb)) +* marking shortcuts no longer conflict with common browser shortcuts ([ec7524a](https://github.com/macite/doubtfire-deploy/commit/ec7524aaae040794de76521363c2d885a0425db0)) +* remove attempt number field ([f0ff40b](https://github.com/macite/doubtfire-deploy/commit/f0ff40bfd7e86b904adae94bf8cbe5d56371e011)) +* remove saved scorm token and always get ([c8fc702](https://github.com/macite/doubtfire-deploy/commit/c8fc702bde6f1c448fc585042e5265625552bae8)) +* retrieve test attempt data correctly ([2810ce6](https://github.com/macite/doubtfire-deploy/commit/2810ce65d423a137600d621a98bf27dbc221921c)) +* send task id with numbas completed attempt data ([e46214d](https://github.com/macite/doubtfire-deploy/commit/e46214dd59d86014bb04d1c31f3a3bf21240e32b)) +* show correct attempts left and allow tutor to review attempt always ([58c24c3](https://github.com/macite/doubtfire-deploy/commit/58c24c3a6760af168a918bc099e755f475eac5f0)) +* show correct Numbas test from the task def with all assets loaded ([bee0a0b](https://github.com/macite/doubtfire-deploy/commit/bee0a0bb1eb905c964caf7888419effe70553520)) +* show delete and download buttons in editor when Numbas test exists ([821feb9](https://github.com/macite/doubtfire-deploy/commit/821feb93a8a40d095ef4f50adedbfd9216278fa9)) +* show Numbas button component and modify iframe request ([c9c2fbe](https://github.com/macite/doubtfire-deploy/commit/c9c2fbe10db156512946355f3cabfe54461f0eba)) +* show Numbas iframe on top of other elements ([f53befd](https://github.com/macite/doubtfire-deploy/commit/f53befd82b52bba24bc8c593a9266c11f9155d32)) +* show previously configured Numbas attempt limit ([56e1a5d](https://github.com/macite/doubtfire-deploy/commit/56e1a5de44ee275f9544b77909b7472f1020c2c3)) +* update numbas api path ([3df59dc](https://github.com/macite/doubtfire-deploy/commit/3df59dcc58f021ef16d81938d1d05473818bc75e)) +* use modal for Numbas and enable authentication ([64b1bfb](https://github.com/macite/doubtfire-deploy/commit/64b1bfb2918993e58a6659948d9621fc7d0b8ba4)) +* use nullish coalescing when retrieving data from the datamodel ([226d919](https://github.com/macite/doubtfire-deploy/commit/226d9193251fb675c92bec8265508477857a4ec9)) + +### [8.0.28](https://github.com/macite/doubtfire-deploy/compare/v8.0.23...v8.0.28) (2024-09-05) + + +### Features + +* add support for the view language ([b4b3654](https://github.com/macite/doubtfire-deploy/commit/b4b36541943232f7df3ee4888bf4ca46c4c04018)) + +### [8.0.23](https://github.com/macite/doubtfire-deploy/compare/v8.0.22...v8.0.23) (2024-08-02) + + +### Features + +* allow pdf download and switch to native viewer ([16ac9c8](https://github.com/macite/doubtfire-deploy/commit/16ac9c8bc488607025ee95dbb4b41134a5346b00)) + + +### Bug Fixes + +* ensure overseer menu only shows when active for task ([c04e9fe](https://github.com/macite/doubtfire-deploy/commit/c04e9fe3a824e316a632b3f7b53b08887e57c831)) + +### [8.0.22](https://github.com/macite/doubtfire-deploy/compare/v8.0.21...v8.0.22) (2024-07-26) + + +### Bug Fixes + +* correct duplicate shortcut registration ([dca03a4](https://github.com/macite/doubtfire-deploy/commit/dca03a41f502947136e301e51242570169826dd9)) + +### [8.0.21](https://github.com/macite/doubtfire-deploy/compare/v8.0.20...v8.0.21) (2024-07-24) + + +### Bug Fixes + +* ensure groups can be locked ([b671065](https://github.com/macite/doubtfire-deploy/commit/b67106589b71660bdfe01151deb68d3092b9091f)) + +### [8.0.20](https://github.com/macite/doubtfire-deploy/compare/v8.0.19...v8.0.20) (2024-07-15) + + +### Bug Fixes + +* ensure turn it in eula is accessible by all ([3d44c11](https://github.com/macite/doubtfire-deploy/commit/3d44c115b498366b80e5b8b99ccd3eaa660ff613)) + +### [8.0.19](https://github.com/macite/doubtfire-deploy/compare/v8.0.18...v8.0.19) (2024-07-10) + + +### Features + +* add ability to minimise task details in task viewer ([e904640](https://github.com/macite/doubtfire-deploy/commit/e9046400e827481e09492bcb458b00b4e3aca347)) + + +### Bug Fixes + +* ensure pdf is visible in task viewer mobile/narrow ([f5388e4](https://github.com/macite/doubtfire-deploy/commit/f5388e45715597f0c92f252f721cf274bb8de0d5)) +* task def editor so save is not over fields and header visible for task being edited ([22a2616](https://github.com/macite/doubtfire-deploy/commit/22a26165c9f2ef634b3e79d1e5d5d6b74e6f2731)) + +### [8.0.18](https://github.com/macite/doubtfire-deploy/compare/v8.0.17...v8.0.18) (2024-07-03) + + +### Features + +* add ability to set unit code on import from rollover ([d47d105](https://github.com/macite/doubtfire-deploy/commit/d47d10561bd7bfad495f878ebb0bab399ce144b7)) + +### [8.0.17](https://github.com/macite/doubtfire-deploy/compare/v8.0.16...v8.0.17) (2024-07-01) + + +### Bug Fixes + +* correct broken template in activities list ([4d81fa1](https://github.com/macite/doubtfire-deploy/commit/4d81fa1fabb07e40d0d42068f23b8e756f4cdf4b)) +* correct campus list templates ([1795895](https://github.com/macite/doubtfire-deploy/commit/17958955f65bab2b268826f2a7e19f311071615b)) +* switch date formats to date-fns ([2394efb](https://github.com/macite/doubtfire-deploy/commit/2394efb07c03da18fb8114d87b0c89e68bf7fd2d)) + +### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-06-28) + + +### Bug Fixes + +* ensure drop works on task resource upload in windows ([f0505d7](https://github.com/macite/doubtfire-deploy/commit/f0505d7b62b97f1b821b19b1c4178973503789da)) + +### [8.0.15](https://github.com/macite/doubtfire-deploy/compare/v8.0.14...v8.0.15) (2024-06-28) + + +### Bug Fixes + +* ensure zip uploads work on windows ([1857bdc](https://github.com/macite/doubtfire-deploy/commit/1857bdc708c81dc39d467f42c9e316a8664dc080)) + +### [8.0.14](https://github.com/macite/doubtfire-deploy/compare/v8.0.13...v8.0.14) (2024-06-27) + + +### Bug Fixes + +* ensure unit import allows unit code change ([01013d3](https://github.com/macite/doubtfire-deploy/commit/01013d3d16ab5b704acc589d34975693030def0b)) +* ensure unit load sets main convenor user in all cases ([4c96624](https://github.com/macite/doubtfire-deploy/commit/4c966245d270af46107aae94bdd38e84b2188b65)) + +### [8.0.13](https://github.com/macite/doubtfire-deploy/compare/v8.0.12...v8.0.13) (2024-06-27) + + +### Bug Fixes + +* update discuss text to promote use ([7b5d35c](https://github.com/macite/doubtfire-deploy/commit/7b5d35c89a577d0408a51d8390400f44615591eb)) + +### [8.0.12](https://github.com/macite/doubtfire-deploy/compare/v8.0.11...v8.0.12) (2024-06-25) + + +### Bug Fixes + +* ensure null fields will not break in entity mapping ([32046e8](https://github.com/macite/doubtfire-deploy/commit/32046e89eaaf2a9b36e88f078a7b695b1506886d)) +* reinstate unit import for teaching period ([991230f](https://github.com/macite/doubtfire-deploy/commit/991230f7b527957116263b6abaa588ed43d3a787)) + +### [8.0.11](https://github.com/macite/doubtfire-deploy/compare/v8.0.10...v8.0.11) (2024-06-24) + + +### Bug Fixes + +* ensure turn it in only appears to task editor when enabled ([3a81688](https://github.com/macite/doubtfire-deploy/commit/3a81688904159c8c9e3efdde8f3605aa5677630f)) +* task date picker allows direct entry ([2f91e8f](https://github.com/macite/doubtfire-deploy/commit/2f91e8fbba7902e1e22871cc82c87f4ff797b058)) + +### [7.0.24](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v7.0.24) (2024-06-05) + + +### Bug Fixes + +* ensure download blob supports 206 responses ([6445f9f](https://github.com/macite/doubtfire-deploy/commit/6445f9f998db70fbe9b9abf723dc17fd298b5d2f)) + +### [8.0.10](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v8.0.10) (2024-06-21) + + +### Bug Fixes + +* ensure loading screen removed in sign in component ([729c438](https://github.com/macite/doubtfire-deploy/commit/729c438f7f6a988f5ff2fa4035493b5cae1c98f7)) +* ensure portfolio can get grades from strings ([fd916b9](https://github.com/macite/doubtfire-deploy/commit/fd916b94e9012c0909c5880f377f93d326c18e4d)) +* ensure portfolio only shown when it exists ([ce970f5](https://github.com/macite/doubtfire-deploy/commit/ce970f5fdc4f42708edc71c98dc9d869056e9e2c)) +* ensure tii open report alerts errors ([c5dd45c](https://github.com/macite/doubtfire-deploy/commit/c5dd45c57fd34e8373f11d065a0cd08edef0a794)) +* fix pdf viewer for portfolios ([da376b9](https://github.com/macite/doubtfire-deploy/commit/da376b9bc7905aadeb4d234cbb4f595e4c4424a1)) +* grade icon for portfolio page ([aab1b9c](https://github.com/macite/doubtfire-deploy/commit/aab1b9c3e7365cdf7dd64d767fdb6e5a9a2436a3)) +* show burndown and pie chart on portfolio page ([e70f4c7](https://github.com/macite/doubtfire-deploy/commit/e70f4c7cd1395eaab942ee389788f75f92e985c9)) + +### [8.0.9](https://github.com/macite/doubtfire-deploy/compare/v7.0.22...v8.0.9) (2024-05-31) + + +### Bug Fixes + +* comment out fix and complete hotkeys temporarily ([c1f623d](https://github.com/macite/doubtfire-deploy/commit/c1f623d17432f3563366ef32fc3da3b54dbef0b7)) + +### [8.0.8](https://github.com/macite/doubtfire-deploy/compare/v8.0.7...v8.0.8) (2024-05-30) + + +### Features + +* added percentage to tooltip when hovering student's task progress ([69ed613](https://github.com/macite/doubtfire-deploy/commit/69ed61380bd7681d4496cb109e628111873b6e82)) + + +### Bug Fixes + +* change from hiding element to not loading ([414da65](https://github.com/macite/doubtfire-deploy/commit/414da65fcef9b10367f53112239a60e1b271d475)) +* change grade values, change grade display ([081c35b](https://github.com/macite/doubtfire-deploy/commit/081c35ba0fbc7ab4ddb2fba3c58892d0e66f325c)) +* fix task inbox shortcuts ([9bc949f](https://github.com/macite/doubtfire-deploy/commit/9bc949fd6dcb71ea165e89de9a4ec9d9347e6562)) +* inbox search box width ([02a99a8](https://github.com/macite/doubtfire-deploy/commit/02a99a8f71033014b26260d3b0dbfca075ca7273)) +* remove pdf viewer on task view when no sheet ([f3e973d](https://github.com/macite/doubtfire-deploy/commit/f3e973dacc5b079ab58da239194d802c5586ca07)) +* revert index changes, html changes for grade ([8f41cd1](https://github.com/macite/doubtfire-deploy/commit/8f41cd1656971963c2035a9249acdde0a257766e)) +* task list scrolling ([0088e9e](https://github.com/macite/doubtfire-deploy/commit/0088e9e245dbd326dea4032239b53eee88754179)) +* use tailwind classes instead of css styling ([42434a5](https://github.com/macite/doubtfire-deploy/commit/42434a5fd4b866781da5d23ecdb0b9b4369aace1)) + +### [8.0.7](https://github.com/macite/doubtfire-deploy/compare/v8.0.6...v8.0.7) (2024-05-26) + + +### Bug Fixes + +* add task description editing ([ee0cfbf](https://github.com/macite/doubtfire-deploy/commit/ee0cfbf7ce804a1806ca5810bad138b97703ebfe)) + +### [8.0.6](https://github.com/macite/doubtfire-deploy/compare/v8.0.5...v8.0.6) (2024-05-25) + + +### Bug Fixes + +* ensure all admin units are fully loaded ([917325e](https://github.com/macite/doubtfire-deploy/commit/917325ed08b89690a7eea0716438673732ba1ec9)) + +### [8.0.5](https://github.com/macite/doubtfire-deploy/compare/v8.0.4...v8.0.5) (2024-05-25) + + +### Bug Fixes + +* ensure (click) is on button, not mat-icon ([99c717d](https://github.com/macite/doubtfire-deploy/commit/99c717d2333de0975da1b3f282195a0b3577a3f6)) + +### [8.0.4](https://github.com/macite/doubtfire-deploy/compare/v8.0.3...v8.0.4) (2024-05-25) + + +### Bug Fixes + +* fix various issues with admin unit list ([3720666](https://github.com/macite/doubtfire-deploy/commit/3720666fb4105bac274449eb468ce34e0f68bae7)) + +### [8.0.3](https://github.com/macite/doubtfire-deploy/compare/v8.0.2...v8.0.3) (2024-05-25) + + +### Features + +* add 4-character abbreviations ([eb62dfc](https://github.com/macite/doubtfire-deploy/commit/eb62dfc90db836870d6c396727fc43c149808e9d)) + +### [8.0.2](https://github.com/macite/doubtfire-deploy/compare/v8.0.1...v8.0.2) (2024-05-25) + + +### Bug Fixes + +* gradeservice bugs ([fd6eb1c](https://github.com/macite/doubtfire-deploy/commit/fd6eb1cd152b72cf297cbd6bd529579858afc543)) +* gradeservice bugs ([7545eb9](https://github.com/macite/doubtfire-deploy/commit/7545eb92b9353d99ac8d8d7d89982cdadf9688b1)) + +### [8.0.1](https://github.com/macite/doubtfire-deploy/compare/v8.0.0...v8.0.1) (2024-05-24) + + +### Features + +* implement live PDF search that updates dynamically as you type ([b9b9945](https://github.com/macite/doubtfire-deploy/commit/b9b9945346d55392e5ee9a6431d85ae92de1bde5)) + + +### Bug Fixes + +* fix critical bugs ([356846e](https://github.com/macite/doubtfire-deploy/commit/356846e5c385c484a6034553366965cde95ec78b)) +* fix splashscreen ([2692b7f](https://github.com/macite/doubtfire-deploy/commit/2692b7f4a3e1ca2a5bc4df3b82a9dfd4aa2ec68a)) + +## [8.0.0](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-6...v8.0.0) (2024-05-23) + + +### Features + +* add multi-badge support ([44c1473](https://github.com/macite/doubtfire-deploy/commit/44c1473700a3d7a4a025d68acac5aa61189d8b52)) +* add synchronised multi-badge ([f70ebdc](https://github.com/macite/doubtfire-deploy/commit/f70ebdca92a05e5ca350d4062a8dc8efba9fd681)) +* add working unit-badge ([dd30247](https://github.com/macite/doubtfire-deploy/commit/dd302478e97228e6bfbfdbee0134abb3eabf2587)) +* add working unit-badge ([c7338ff](https://github.com/macite/doubtfire-deploy/commit/c7338ffd88edb457a3443b43ea21706c43231973)) +* qol improvements for unit codes ([f7f928e](https://github.com/macite/doubtfire-deploy/commit/f7f928e485448a69b054dca94f07d623f84e328f)) +* small fixes to home and unit code ([918e804](https://github.com/macite/doubtfire-deploy/commit/918e8047745b489aae1fafdc67720568dd8d829e)) + + +### Bug Fixes + +* add missing imports ([659b52c](https://github.com/macite/doubtfire-deploy/commit/659b52c82a26b9496a3dba81401b5147d05248ae)) +* change time exceeded to feedback exceeded ([673619d](https://github.com/macite/doubtfire-deploy/commit/673619d99f177d834fba3643171426092e0d05e0)) +* correct task resource upload actions ([5e9c9b1](https://github.com/macite/doubtfire-deploy/commit/5e9c9b1d05d6d6975fd4ba3a3176314ddd7d8514)) +* ensure loading state changed after projects and unit roles load ([9171d0c](https://github.com/macite/doubtfire-deploy/commit/9171d0c2c37c17d26f464f6aa0ba7c479851e6eb)) +* ensure staff task list checks unit exists ([dbb312d](https://github.com/macite/doubtfire-deploy/commit/dbb312dc3c5c9e2be24161914e8d95e1a5c1bc53)) +* ensure unit load updates unit object if it already exists ([e48ffad](https://github.com/macite/doubtfire-deploy/commit/e48ffadf63891212c3e40ab696d54a3935485b08)) +* hide overseer settings if automation disabled ([0c08fe3](https://github.com/macite/doubtfire-deploy/commit/0c08fe3e82a78dd1e91fb44ce6008fb5298c46ee)) +* slide unit code off left side ([8cd57b5](https://github.com/macite/doubtfire-deploy/commit/8cd57b589812fd59c6da4de02246791fb4410959)) +* sort units desc by start date ([9b78856](https://github.com/macite/doubtfire-deploy/commit/9b788561372a3ddf065d3b28e547a2194ef29655)) +* zip upload for overseer ([5ad2085](https://github.com/macite/doubtfire-deploy/commit/5ad2085b2d730235f61e7b7c603727d8b6736cf2)) + +## [8.0.0-6](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-5...v8.0.0-6) (2024-05-13) + +## [8.0.0-5](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-4...v8.0.0-5) (2024-05-13) + +## [8.0.0-4](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-3...v8.0.0-4) (2024-05-11) + + +### Features + +* add task badge ([b48cd4c](https://github.com/macite/doubtfire-deploy/commit/b48cd4c99333e41c0c1d32531e571d32bb482a81)) + + +### Bug Fixes + +* (WIP) fix alert service migration ([3d9f4dc](https://github.com/macite/doubtfire-deploy/commit/3d9f4dc05e7a45884dc383e0f5ed4bdb09b0558d)) +* add max length validator and change reason field to text-area ([6227200](https://github.com/macite/doubtfire-deploy/commit/6227200566c3f608c279e92a3f255a7e94148c1d)) +* address linter issues in task.ts ([14e9699](https://github.com/macite/doubtfire-deploy/commit/14e9699bdfe336f1e3f3cce3d722c835d58f3cdb)) +* copy dist browser to nginx html ([08fa919](https://github.com/macite/doubtfire-deploy/commit/08fa91937e028cb3ee093709e5a31f94da44fc33)) +* correct filenames for grotesk fonts ([9bedd81](https://github.com/macite/doubtfire-deploy/commit/9bedd812b12628df9cb32e48cb91a88b5cdf69b1)) +* ensure eula state remains visible ([131540c](https://github.com/macite/doubtfire-deploy/commit/131540ca4b934773afd9f72aa2578579048ed6a2)) +* ensure unit admin shows all units ([02b7a15](https://github.com/macite/doubtfire-deploy/commit/02b7a15bbbd2306a61e344f995dffb72a3915498)) +* fix course progress bar on firefox ([ae5c1e0](https://github.com/macite/doubtfire-deploy/commit/ae5c1e0b5901bae0411cf7bbaa32ee8f340b908a)) +* fix incorrect projcets listed in dropdown ([6a7e478](https://github.com/macite/doubtfire-deploy/commit/6a7e4788b522e5af6331a82ed33e9c9137d2ca86)) +* fix margin issue on dropdown ([c8145f0](https://github.com/macite/doubtfire-deploy/commit/c8145f0972a03e52377e0203cabb2cf6353db8b3)) +* grade and quality point display on task-assessment-card ([7cba502](https://github.com/macite/doubtfire-deploy/commit/7cba502e002143e8255bf0d786551bd270f73f0e)) +* indicate mandatory fields in upload-submission-modal ([e8801e2](https://github.com/macite/doubtfire-deploy/commit/e8801e2a64fe15ad423d9017d10e5e23f6e00eda)) +* only check grade if it exists ([1c213c5](https://github.com/macite/doubtfire-deploy/commit/1c213c53571f79563e9a071e2dd9645598382522)) +* remove unused imports in extension-modal.service ([8081f51](https://github.com/macite/doubtfire-deploy/commit/8081f51b5f28ea511b9f76d026ae63f16153ae2c)) +* use tailwindcss classes ([8d7e160](https://github.com/macite/doubtfire-deploy/commit/8d7e160e2d40c42284ee0c1fc85d6d9e01166cda)) + +## [8.0.0-3](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-2...v8.0.0-3) (2024-05-02) + + +### Bug Fixes + +* reenable eula html fetch ([cda9e52](https://github.com/macite/doubtfire-deploy/commit/cda9e52a259bfaa27e8252f40e579d11d1af280c)) + +## [8.0.0-2](https://github.com/macite/doubtfire-deploy/compare/v7.0.21...v8.0.0-2) (2024-05-01) + + +### Features + +* accept promela files ([df93a69](https://github.com/macite/doubtfire-deploy/commit/df93a69e45d2d9e41b9cf0802d521a3663d7a36c)) +* migrate unit list in all locations ([6651d00](https://github.com/macite/doubtfire-deploy/commit/6651d0011446fdde7179c5173f902ce2e4ea7545)) +* remove misleading progress statement ([63e276c](https://github.com/macite/doubtfire-deploy/commit/63e276c041f77d8b401d24a4f49896cfa2095442)) + + +### Bug Fixes + +* correct change detection on task def ([55daff2](https://github.com/macite/doubtfire-deploy/commit/55daff234441a242d96de097c2b2912df0c6c9a8)) +* correct npm install for dev container image ([5126c3b](https://github.com/macite/doubtfire-deploy/commit/5126c3ba7fed55217e88c54c25dc70595ec4c666)) +* ensure npm will force install ([f91751e](https://github.com/macite/doubtfire-deploy/commit/f91751eae788bc3f65d33b610ed80c96d3978974)) +* fix firefox-specific bug ([6b6054b](https://github.com/macite/doubtfire-deploy/commit/6b6054bd5c1104a96ccac413a7115009eeba8d2f)) +* remove ngClass ([d1d8c72](https://github.com/macite/doubtfire-deploy/commit/d1d8c72ace21551a68bd4d0a8ba88eabb2ebdb9d)) +* remove plagiarism checks ([21b02fb](https://github.com/macite/doubtfire-deploy/commit/21b02fb7cc616090f1fb2d26f65b336072f9105b)) +* remove the incorrect option from for scrollIntoView() ([9e752fe](https://github.com/macite/doubtfire-deploy/commit/9e752fe9d49df786ceb3e7007cbf0aad57809604)) +* remove unused loading from f-units ([c4c38fa](https://github.com/macite/doubtfire-deploy/commit/c4c38fad4fbdfe248e383cf247f949197ad0a047)) +* typo ([820c56f](https://github.com/macite/doubtfire-deploy/commit/820c56f3a1bc30b7637b98e6f80b406ca350b5b8)) + +## [8.0.0-1](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-0...v8.0.0-1) (2024-03-21) + + +### Bug Fixes + +* update deploy dockerfile ([41a5161](https://github.com/macite/doubtfire-deploy/commit/41a5161b356931eafd8e4caf256f311f10bc8bb4)) + +## [8.0.0-0](https://github.com/macite/doubtfire-deploy/compare/v7.0.18...v8.0.0-0) (2024-03-21) + + +### Features + +* (wip) add similarities notification ([8e4a198](https://github.com/macite/doubtfire-deploy/commit/8e4a198a037de832bbebe96e309c4c8485d076cc)) +* add ability to accept tii eula to model ([0106b01](https://github.com/macite/doubtfire-deploy/commit/0106b01ed249139cbe06096f95a36b5d11bcd0ac)) +* add ability to accept turn it in eula ([380ad1e](https://github.com/macite/doubtfire-deploy/commit/380ad1e93252f8f928893626b65f4dab01813524)) +* add ability to open turnitin viewer ([5248e80](https://github.com/macite/doubtfire-deploy/commit/5248e80622e55b79ce4d7b35f8202ee8099c2dce)) +* add ability to update similarity flag ([de005ee](https://github.com/macite/doubtfire-deploy/commit/de005ee98a270998e2175109783cab72b92e36f3)) +* add dynamic footer ([3c62fe0](https://github.com/macite/doubtfire-deploy/commit/3c62fe06d009c3b752259f50887c625c98a371cd)) +* add empty pdf view to new task dashboard ([9c3cdfb](https://github.com/macite/doubtfire-deploy/commit/9c3cdfbb93711a6ae911ed461651200d8c75db48)) +* add file drop component ([c211003](https://github.com/macite/doubtfire-deploy/commit/c211003004ae6c7505158a65ce2006b219920827)) +* add footer content ([735c43b](https://github.com/macite/doubtfire-deploy/commit/735c43b5c2df7e8f367310ad92ef716fd5140375)) +* add link to student task from inbox ([d4301e0](https://github.com/macite/doubtfire-deploy/commit/d4301e0d1f2f6ec4c563801a7f0d1132884f9989)) +* add mobile inbox view ([56ded70](https://github.com/macite/doubtfire-deploy/commit/56ded707e638ae769665a863ce65acffea5a588a)) +* add multi-file support to f-upload ([d181969](https://github.com/macite/doubtfire-deploy/commit/d181969198e2b7611e3f0e330577b825e99a248f)) +* add new file upload component ([891ab20](https://github.com/macite/doubtfire-deploy/commit/891ab20eb6f1d545ff58d0157fdd9912b9546c9f)) +* add new inbox component ([ec0f62c](https://github.com/macite/doubtfire-deploy/commit/ec0f62c488ae3e99e9487ea1ab87f5bb2f1fbed7)) +* add new pdf-viewer ([617fbd2](https://github.com/macite/doubtfire-deploy/commit/617fbd24f8424541aeb87b16651f06737b570633)) +* add new similarity component ([48ba01c](https://github.com/macite/doubtfire-deploy/commit/48ba01c8d780a04a1f526f89fcd9bc63ef5d4aec)) +* add new task assessment card ([ac3b50f](https://github.com/macite/doubtfire-deploy/commit/ac3b50f29b8a2722d09ad94a2f82bb54c1c32da7)) +* add new task dashboard component ([dc841f9](https://github.com/macite/doubtfire-deploy/commit/dc841f9e7af811a3a56a0c21fd3b3968ec7aead9)) +* add new task due card ([3ade5ea](https://github.com/macite/doubtfire-deploy/commit/3ade5ea34eb3c2c756d7df0f7a6c250fa50290bb)) +* add new task due card content ([c43ea3e](https://github.com/macite/doubtfire-deploy/commit/c43ea3e27abdf253596bfedd5112f5ef7a7b929d)) +* add new task submission card ([6d27690](https://github.com/macite/doubtfire-deploy/commit/6d2769029413f84b73c7c825d16e9a3366142177)) +* add pdf search and zoom ([f83ce57](https://github.com/macite/doubtfire-deploy/commit/f83ce570e80dc20d118288c6d32c2d2a9ca263b5)) +* add resizable inbox panels ([4920e31](https://github.com/macite/doubtfire-deploy/commit/4920e31ce366c3dfb4340ab4da159b176381cf49)) +* add resizable panels to inbox ([5abda03](https://github.com/macite/doubtfire-deploy/commit/5abda039af5b2d3b5e2589c4864b2e1715c5e8c0)) +* add rest of layout to footer ([3b9de7c](https://github.com/macite/doubtfire-deploy/commit/3b9de7cc6d923a0e6431524f2967b5e3bc360a6f)) +* add selected task sheet url ([00a7fb5](https://github.com/macite/doubtfire-deploy/commit/00a7fb516d362d3725b915d012878a9ccf8ef009)) +* add selectedTask service ([02aa41a](https://github.com/macite/doubtfire-deploy/commit/02aa41a34232359d1366d841d1236a068a837ae5)) +* add similarities staff dashboard switch ([1ec0b72](https://github.com/macite/doubtfire-deploy/commit/1ec0b72c26cc27bd4d17376af5b47650d28bbc10)) +* add similarity flags to view ([8c7975c](https://github.com/macite/doubtfire-deploy/commit/8c7975cadd14e6d3390cfa9917983cd01498a69c)) +* add simple project progress bar ([73fda77](https://github.com/macite/doubtfire-deploy/commit/73fda776ee36c6574c1ddc0dc09b958d61de3000)) +* add start of new similarity view ([a1e51b6](https://github.com/macite/doubtfire-deploy/commit/a1e51b6bc7030086a1d7a4d715f23b3e76f7ddb3)) +* add task plagairism warning on inbox ([6bd8620](https://github.com/macite/doubtfire-deploy/commit/6bd8620f5473db4517e38fd0487ab5876f921a36)) +* add teaching period remove break function ([90c6a37](https://github.com/macite/doubtfire-deploy/commit/90c6a3730f84da9e64abec676bcdf66c10b7fc60)) +* add tii action log ([96d982d](https://github.com/macite/doubtfire-deploy/commit/96d982d5fb945bdbf9ea8b6d534a5dd18ab64ad7)) +* add unselected user icon badge in inbox ([794697b](https://github.com/macite/doubtfire-deploy/commit/794697b53d6ee81f57b37b173d03a0688c6993b5)) +* complete mobile task inbox view ([00a4b3f](https://github.com/macite/doubtfire-deploy/commit/00a4b3f1e8f52364a83b6affae34295da4a7af34)) +* disable hover on task inbox for mobile ([a59fd01](https://github.com/macite/doubtfire-deploy/commit/a59fd0153de8b1f9e9b9022d0f6df1032c92f8d1)) +* downgrade task due card ([c342ac2](https://github.com/macite/doubtfire-deploy/commit/c342ac2e3cc4213c2b92499bc4a191485184af37)) +* enhance task search with similarity flags ([65ad918](https://github.com/macite/doubtfire-deploy/commit/65ad91842882e76379033350f90b966d874c6ba4)) +* enhance ui/ux of task inbox screen ([6b275c3](https://github.com/macite/doubtfire-deploy/commit/6b275c3cd5d575a399e901d52a62808238c6d0e4)) +* expand new file uplaoder ([11d798d](https://github.com/macite/doubtfire-deploy/commit/11d798d6a6e5eca4555a7d141e1d11d2a862fcfe)) +* finish new alerts service ([3beb059](https://github.com/macite/doubtfire-deploy/commit/3beb05987e605c9f4270fc0d7bdd95f82bf64007)) +* make all datetime in aus format ([7a0f749](https://github.com/macite/doubtfire-deploy/commit/7a0f749a4328a44c1ffb5692017dfa39a061e1d5)) +* migrate new unit dialog ([0a2a1e9](https://github.com/macite/doubtfire-deploy/commit/0a2a1e9baca6b0553730c1a939b246bf1be178a3)) +* minor improvements to file-drop ([73139be](https://github.com/macite/doubtfire-deploy/commit/73139be83449f50036eedb3520ed2d8daa5da09c)) +* new footer component ([c3b4c18](https://github.com/macite/doubtfire-deploy/commit/c3b4c182921079d6ebc0851ec7e6515e65f1c15b)) +* new grade service ([31073e1](https://github.com/macite/doubtfire-deploy/commit/31073e1dbe963c1e0f2c84139a2c3f746cc31bbb)) +* new student user badge ([97c84d3](https://github.com/macite/doubtfire-deploy/commit/97c84d3016b0e322d54062fae0d46da112146d5d)) +* new task status card ([78218cf](https://github.com/macite/doubtfire-deploy/commit/78218cf6d45f5cac50203f96109d27400fa37686)) +* only download similarity resource on view ([563d102](https://github.com/macite/doubtfire-deploy/commit/563d1024ee7023e4228a9ceef9f556e48e7127d1)) +* progress redesigned inbox ([f1b672b](https://github.com/macite/doubtfire-deploy/commit/f1b672b7495a9086abb88f5e1991cb4c4f7b60c1)) +* register new inbox component ([3d79baa](https://github.com/macite/doubtfire-deploy/commit/3d79baae505e44c401179ae34de4804e8d90b7ba)) +* show TII accepted status in profile ([7b5c3e2](https://github.com/macite/doubtfire-deploy/commit/7b5c3e2c0fe9fcc30f9fffc73d9a942714db7cb2)) +* small change to task view ([f640920](https://github.com/macite/doubtfire-deploy/commit/f6409201e9d4af4f075b4db8559fc1e26f4a374f)) +* small changes to user table ([18957ac](https://github.com/macite/doubtfire-deploy/commit/18957acfc700e941ebb161d9ddb8f5e1ebe1beff)) +* trigger window resize when pdf loads ([044c170](https://github.com/macite/doubtfire-deploy/commit/044c170ebe05e7e3a368df2e8041884d2e23c752)) +* update file viewer to use file download and blobs ([8751123](https://github.com/macite/doubtfire-deploy/commit/87511232ca384a355ddfc5eb396186babd676f92)) +* wip add file uploader component ([48c73f5](https://github.com/macite/doubtfire-deploy/commit/48c73f547892ae3ce12fdac416bf93c3a2c72006)) + + +### Bug Fixes + +* add activeUntil date mapping to tps ([2cae20a](https://github.com/macite/doubtfire-deploy/commit/2cae20a6b3fa3e5ea8a001ffa40a87263c438b68)) +* add arbitrary task argument to `togglePin` in task inbox ([6e1784f](https://github.com/macite/doubtfire-deploy/commit/6e1784ff52a745330e57f2ccc2a55b3206d535d0)) +* add seperator to naviation on mobile ([fc4f052](https://github.com/macite/doubtfire-deploy/commit/fc4f0527b144fd8f3b6e98b335e629f85fe1bb3b)) +* add the correct enterkeyhint to the comment composer ([569db05](https://github.com/macite/doubtfire-deploy/commit/569db059fc9786363b1b62d7be72e44f711faba3)) +* add unloaded state to progressbar ([2c3a28e](https://github.com/macite/doubtfire-deploy/commit/2c3a28e9718879f55596221517db35bda8c09450)) +* adjust due card layout ([0360a6e](https://github.com/macite/doubtfire-deploy/commit/0360a6e0868e995d7ba5c9091be556dad4bfd474)) +* always display shortened task name in header ([a05c8ff](https://github.com/macite/doubtfire-deploy/commit/a05c8ffd9aef9c865f72458157b465f9de1e07f3)) +* center pins along items in new task inbox ([6b3c0d2](https://github.com/macite/doubtfire-deploy/commit/6b3c0d2b1d5541fe36c6fbd03dfc752f43d03e18)) +* center placeholder text in task inbox search bar & reduce padding on far-right ([ffec9b6](https://github.com/macite/doubtfire-deploy/commit/ffec9b6f4bfc9d2aee6aa762c41bcce1ed1823ba)) +* center student and task name on bottom left screen ([e986199](https://github.com/macite/doubtfire-deploy/commit/e9861992e9e5a40076973a2215bcc919c1777b5d)) +* center view all units button on home page ([9807dfd](https://github.com/macite/doubtfire-deploy/commit/9807dfd1f18e1efc9f882a67ef99f1d198a03ff7)) +* centering of Administration icons on home page ([1043f74](https://github.com/macite/doubtfire-deploy/commit/1043f74e2ca5d23cad8c4d890a202b20ddb4bc37)) +* change display name of student on bottom left screen from being nickname to full name ([5fe7790](https://github.com/macite/doubtfire-deploy/commit/5fe7790e23aec709f8be5a444bf84ebdf77c9ce5)) +* change shown name on messages in chat to be student's full name ([93636c4](https://github.com/macite/doubtfire-deploy/commit/93636c400c1850e20320a57be010347541c5137c)) +* chatbox spacing, placement of messages <> photos, distance between message & name ([dd9cb2a](https://github.com/macite/doubtfire-deploy/commit/dd9cb2ab3bdde886c2f297d8044986427febd366)) +* ensure accepted TII eula details are retained ([e60ae54](https://github.com/macite/doubtfire-deploy/commit/e60ae547121f33edd7cc8d8c5d4afd27a1f90e8c)) +* ensure blobs are freed on destroy ([ee017eb](https://github.com/macite/doubtfire-deploy/commit/ee017eb00a506c81a108ce6dec52f7f91064d350)) +* ensure font is set to roboto ([a6ff4ce](https://github.com/macite/doubtfire-deploy/commit/a6ff4cee9794e37a208af28d7d085182441fa555)) +* ensure loadedUnitRoles is public in global ([b92159f](https://github.com/macite/doubtfire-deploy/commit/b92159ff33cf9537c0ccec50d57a54636315bec4)) +* ensure logout in timeout always signs out ([3380075](https://github.com/macite/doubtfire-deploy/commit/33800759083156682014f0f63bc83a0283ae96fa)) +* ensure mat menu icons have correct tags ([f971ad1](https://github.com/macite/doubtfire-deploy/commit/f971ad1cf7fa56de0f4e97e9533a0567db897da4)) +* ensure only staff need to accept turn it in EULA ([029c40b](https://github.com/macite/doubtfire-deploy/commit/029c40b556bb1709e75547615b2d1a1109997a74)) +* ensure pdf actions loads after pdf loaded ([0425c54](https://github.com/macite/doubtfire-deploy/commit/0425c5465a678509e1a8d719fef39975c4d8e9e5)) +* ensure similarities without files still view ([5794e2f](https://github.com/macite/doubtfire-deploy/commit/5794e2fb345328396517a7d2f945cfabb1c37173)) +* ensure task pdf viewer works ([d3d1bf8](https://github.com/macite/doubtfire-deploy/commit/d3d1bf8564c6e6134130b44df90bef42430f4654)) +* ensure task submission status updated on init ([ca77c92](https://github.com/macite/doubtfire-deploy/commit/ca77c92d251bf4087964886579de642f6f300b9a)) +* ensure that timeout state not re-routed ([c16ee90](https://github.com/macite/doubtfire-deploy/commit/c16ee90c2c372ea1889d3470e2be510aefd2245f)) +* ensure welcome page still can go to timeout ([5253f2e](https://github.com/macite/doubtfire-deploy/commit/5253f2eb6fce1de1b6df585589f1cc2594ac87a8)) +* excessive spacing below unit tags on home page ([1bfaa21](https://github.com/macite/doubtfire-deploy/commit/1bfaa216440d880d82875f519e9b3f0f59ddcc23)) +* fix few type errors ([8a96e5b](https://github.com/macite/doubtfire-deploy/commit/8a96e5b33a095cd70222719b33d7dc853d67f347)) +* fix file drop to support click to upload ([599cd9e](https://github.com/macite/doubtfire-deploy/commit/599cd9e82c1518113374f0675fc54dd1483fcc85)) +* fix footer height not resetting on similarity ([19c43d7](https://github.com/macite/doubtfire-deploy/commit/19c43d7945c5848d1ca511e146fefdfa9735c49b)) +* fix incorrect closing tag ([ad28818](https://github.com/macite/doubtfire-deploy/commit/ad28818fba9dac552a2adf14785c5bbf98b4e206)) +* fix page height recalculation trigger ([8f219c3](https://github.com/macite/doubtfire-deploy/commit/8f219c31e9a3461626a9344352c4d7aa68c57c43)) +* fix various build issues ([8b947ae](https://github.com/macite/doubtfire-deploy/commit/8b947aeea1cb0dfa4bac8e22ff5bdb2a9a82ec49)) +* fix various task comment composer/display issues ([5670bf1](https://github.com/macite/doubtfire-deploy/commit/5670bf1dcd77e8010fe88bf24662ec96e4e29847)) +* hide extension for staff if can't apply ([1699e50](https://github.com/macite/doubtfire-deploy/commit/1699e50f2d7424361e0f7d5a173bdd9fffd87c24)) +* initialise inbox on return ([1249e96](https://github.com/macite/doubtfire-deploy/commit/1249e96f53ef9544cd81e3f2c3f1d5acf4a628f3)) +* initialise inbox view ([1ae4ac9](https://github.com/macite/doubtfire-deploy/commit/1ae4ac9b304348f5528368d87ded3c26e8e5cf40)) +* issues with UI in photo spacing and text alignment ([716ead3](https://github.com/macite/doubtfire-deploy/commit/716ead3497a8a2ecd1050484bd289c003a47dffa)) +* make photo in chatbox fall to bottom ([aa4e814](https://github.com/macite/doubtfire-deploy/commit/aa4e81446546f1e62b08fd74ba8ac1e563e5efc8)) +* make read receipt smaller to fix message alignment ([c869458](https://github.com/macite/doubtfire-deploy/commit/c869458cd45334e009ae83ab3c911033bc1987b9)) +* null input checks on migrated cards ([7a192af](https://github.com/macite/doubtfire-deploy/commit/7a192af22bf1eef026d05a16edcc3a97c6abbebf)) +* pass selected task to footer's user icon ([28782b1](https://github.com/macite/doubtfire-deploy/commit/28782b134cb03f5c334df48e8887f81393661bda)) +* photo from below message to being inline ([0e97a03](https://github.com/macite/doubtfire-deploy/commit/0e97a03a491f4137ec301dd18a42130a845ebe37)) +* reduce user badge clickable region ([7305f86](https://github.com/macite/doubtfire-deploy/commit/7305f866a9582e10dd870fad1861de4ce209a4e0)) +* regenerate user icons on input changes ([257ab4e](https://github.com/macite/doubtfire-deploy/commit/257ab4eb63ec15de545193f8b60176ac33e17b01)) +* remove call to teaching period name ([1e2e019](https://github.com/macite/doubtfire-deploy/commit/1e2e0198a32acd59c11932fde2a2f14a5bacf48f)) +* remove dupe case in transition hook ([9808798](https://github.com/macite/doubtfire-deploy/commit/98087981e06296a1eb9a17f527c49ab9b27caef3)) +* remove incorrect aria hidden tags ([46bfe21](https://github.com/macite/doubtfire-deploy/commit/46bfe2109e4b912a146201572671ff759fc02226)) +* remove no PDF text from overlapping with icon ([c6543cf](https://github.com/macite/doubtfire-deploy/commit/c6543cf2f9be9644b7382eeb64699e15e461447a)) +* remove old teaching periods from home ([4f4a617](https://github.com/macite/doubtfire-deploy/commit/4f4a6175f39ac9df75c7efe920ffcc15576cc98e)) +* remove pct copy data ([6bb96b4](https://github.com/macite/doubtfire-deploy/commit/6bb96b49f436a7d4bd6f5e587b30a8528e6d75b7)) +* remove user badge from old task panel ([9129956](https://github.com/macite/doubtfire-deploy/commit/9129956f41b78a8e3e84ffe9a124a7941d8905c1)) +* require eula for any user ([daf7ba9](https://github.com/macite/doubtfire-deploy/commit/daf7ba9d9056c262cafc871b623c59a0ef837274)) +* resolved issue with intelligent discussion ([18cd1fc](https://github.com/macite/doubtfire-deploy/commit/18cd1fc6f0443c353fc5f49c81dafd2428901cbc)) +* resolved issue with intelligent-discussion-dialog component rendering ([1efa758](https://github.com/macite/doubtfire-deploy/commit/1efa758fd813751788cc79fe30e01ca8a09013d8)) +* shrink header menu on small screens ([580445d](https://github.com/macite/doubtfire-deploy/commit/580445d25573bf00671246269c61685917c34867)) +* spacing (of own/person messaging) is now right/left aligned respectively ([7d10aa0](https://github.com/macite/doubtfire-deploy/commit/7d10aa0f58e2d7c8e8fd45439d8c464fabe3508c)) +* split header onto seperate lines on small screens ([d8a9016](https://github.com/macite/doubtfire-deploy/commit/d8a90168e58ef8d71f31f76d999d4f6a59232987)) +* switch max pct to similarity flag in project ([094b418](https://github.com/macite/doubtfire-deploy/commit/094b418c1bff709e755bf7c61207ebf22bfc6106)) +* task explorer 405 error ([7ea516c](https://github.com/macite/doubtfire-deploy/commit/7ea516ce8e346d46e8acf68c8b41fa81485515ba)) +* task submission pdf downloading ([b0becb4](https://github.com/macite/doubtfire-deploy/commit/b0becb4c76e4e45f10782561a6b53a322eb43665)) +* tweak theme.scss file ([393770b](https://github.com/macite/doubtfire-deploy/commit/393770b35d1688d27bce47e1d6b94735a1822494)) +* update package lock ([674f3c7](https://github.com/macite/doubtfire-deploy/commit/674f3c70bd0a4c8c33e25d34beeab76c29f56325)) +* use angular 15 ([d0104cc](https://github.com/macite/doubtfire-deploy/commit/d0104cc57edda68a1a165bdf1fd7cf75bd74ec68)) +* use correct task object in task pinning ([a5fceb0](https://github.com/macite/doubtfire-deploy/commit/a5fceb048b931dbd5ccc3ad5d4fd898b146284fb)) +* use correct theming import ([b0d3232](https://github.com/macite/doubtfire-deploy/commit/b0d3232eaed2096296cf025437dda26ddcd595e0)) +* use disabled blinding ([628ca55](https://github.com/macite/doubtfire-deploy/commit/628ca55b4e8f569f751b78ead7a50fa9e086ccec)) +* use new state name in task dropdown ([3c2fe44](https://github.com/macite/doubtfire-deploy/commit/3c2fe444d398bcedb5c998a47683d04279996680)) +* use onChanges rather than input setter ([8069c21](https://github.com/macite/doubtfire-deploy/commit/8069c21d9ecfc412dea37cade8e8a37e79730f01)) + ### [8.0.9](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.8...v8.0.9) (2024-05-31) @@ -328,8 +1707,15 @@ All notable changes to this project will be documented in this file. See [standa * use tailwindcss classes ([8d7e160](https://github.com/macite/doubtfire-deploy/commit/8d7e160e2d40c42284ee0c1fc85d6d9e01166cda)) -### [7.0.23](https://github.com/macite/doubtfire-deploy/compare/v7.0.22...v7.0.23) (2024-06-04) +### [7.0.24](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v7.0.24) (2024-06-05) + +### Bug Fixes +* ensure download blob supports 206 responses ([6445f9f](https://github.com/macite/doubtfire-deploy/commit/6445f9f998db70fbe9b9abf723dc17fd298b5d2f)) + + + +### [7.0.23](https://github.com/macite/doubtfire-deploy/compare/v7.0.22...v7.0.23) (2024-06-04) ### Bug Fixes diff --git a/JPlag-Report-Viewer b/JPlag-Report-Viewer new file mode 160000 index 0000000000..4132c30d9e --- /dev/null +++ b/JPlag-Report-Viewer @@ -0,0 +1 @@ +Subproject commit 4132c30d9ed5606df4648a7f1494ca751d3dca49 diff --git a/README.md b/README.md index b213dcce33..5f4e969966 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A modern, lightweight learning management system. SUMMARY: -73 / 132 components migrated +74 / 132 components migrated MIGRATED: @@ -64,6 +64,7 @@ MIGRATED: - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +- [x] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts - [x] ./src/app/units/states/analytics/unit-analytics-route.component.ts - [x] ./src/app/common/footer/footer.component.ts - [x] ./src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts @@ -91,6 +92,8 @@ MIGRATED: - [x] ./src/app/common/services/alert.service.ts - [x] ./src/app/sessions/states/sign-in/sign-in.component.ts - [x] ./src/app/account/edit-profile/edit-profile.component.ts +- [x] ./src/app/groups/group-set-selector/group-set-selector.component.ts +- [x] ./src/app/admin/modals/create-unit-modal/create-unit-modal.coffee TODO: @@ -164,7 +167,6 @@ TODO: - [ ] ./src/app/groups/group-set-manager/group-set-manager.coffee - [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee - [ ] ./src/app/groups/group-member-list/group-member-list.coffee -- [ ] ./src/app/groups/group-set-selector/group-set-selector.coffee - [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee - [ ] ./src/app/groups/groups.coffee - [ ] ./src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.coffee @@ -188,7 +190,6 @@ TODO: - [ ] ./src/app/units/states/edit/directives/directives.coffee - [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee - [ ] ./src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee -- [ ] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee - [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee - [ ] ./src/app/units/states/edit/edit.coffee - [ ] ./src/app/units/states/rollover/directives/directives.coffee diff --git a/angular.json b/angular.json index 2c0b1f0b92..6a528bd8c1 100644 --- a/angular.json +++ b/angular.json @@ -24,8 +24,21 @@ "tsConfig": "src/tsconfig.app.json", "assets": [ "src/assets", - "src/manifest.webmanifest" + "src/manifest.webmanifest", + { + "input": "./JPlag-Report-Viewer", + "output": "/JPlag", + "glob": "**/!(*.gitignore|README.md|.git)" + }, + { + "glob": "**/*", + "input": "./node_modules/monaco-editor/min", + "output": "/assets/monaco/min/" + } ], + "loader": { + ".ttf": "binary" + }, "styles": [ "src/theme.scss", "src/styles.scss", @@ -36,7 +49,8 @@ "./build/assets/node_modules/codemirror/lib/codemirror.css", "./build/assets/node_modules/codemirror/theme/xq-light.css", "./build/assets/node_modules/nvd3/build/nv.d3.css", - "node_modules/@ctrl/ngx-emoji-mart/picker.css" + "node_modules/@ctrl/ngx-emoji-mart/picker.css", + "node_modules/@worktile/gantt/styles/index.scss" ], "scripts": [ "node_modules/moment/moment.js", @@ -68,8 +82,8 @@ "with": "src/environments/environment.prod.ts" }, { - "replace": "src/app/config/constants/apiURL.ts", - "with": "src/app/config/constants/apiURL.prod.ts" + "replace": "src/app/config/constants/hostUrl.ts", + "with": "src/app/config/constants/hostUrl.prod.ts" } ], "optimization": true, @@ -89,8 +103,8 @@ "sourceMap": true, "fileReplacements": [ { - "replace": "src/app/config/constants/apiURL.ts", - "with": "src/app/config/constants/apiURL.devcontainer.ts" + "replace": "src/app/config/constants/hostUrl.ts", + "with": "src/app/config/constants/hostUrl.devcontainer.ts" } ] } @@ -138,29 +152,19 @@ "./node_modules/ngx-bootstrap/datepicker/bs-datepicker.css" ], "scripts": [], - "assets": [ - "src/favicon.ico", - "src/assets", - "src/manifest.webmanifest" - ] + "assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": [ - "src/**/*.ts", - "src/**/*.component.html" - ] + "lintFilePatterns": ["src/**/*.ts", "src/**/*.component.html"] } }, "eslint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": [ - "src/**/*.ts", - "src/**/*.component.html" - ] + "lintFilePatterns": ["src/**/*.ts", "src/**/*.component.html"] } } } @@ -182,8 +186,6 @@ "cache": { "enabled": true }, - "schematicCollections": [ - "@angular-eslint/schematics" - ] + "schematicCollections": ["@angular-eslint/schematics"] } } diff --git a/deploy.Dockerfile b/deploy.Dockerfile index 2326fca4ec..9aa69355e3 100644 --- a/deploy.Dockerfile +++ b/deploy.Dockerfile @@ -17,7 +17,7 @@ RUN npm run-script deploy ## STAGE 2: Host ### -FROM nginx:1.21.5-alpine +FROM nginx:1.29.0-alpine # Remove the default Nginx configuration file RUN rm -v /etc/nginx/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index b97ff4e52c..9019dbcc4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: RAILS_ENV: 'development' DF_STUDENT_WORK_DIR: /student-work - DF_INSTITUTION_HOST: http://localhost:3000 + DF_INSTITUTION_HOST: http://localhost:4200 DF_INSTITUTION_PRODUCT_NAME: OnTrack DF_SECRET_KEY_BASE: test-secret-key-test-secret-key! @@ -24,8 +24,8 @@ services: # Authentication method - can set to AAF or ldap DF_AUTH_METHOD: database DF_AAF_ISSUER_URL: https://rapid.test.aaf.edu.au - DF_AAF_AUDIENCE_URL: http://localhost:3000 - DF_AAF_CALLBACK_URL: http://localhost:3000/api/auth/jwt + DF_AAF_AUDIENCE_URL: http://localhost:4200 + DF_AAF_CALLBACK_URL: http://localhost:4200/api/auth/jwt DF_AAF_IDENTITY_PROVIDER_URL: https://signon-uat.deakin.edu.au/idp/shibboleth DF_AAF_UNIQUE_URL: https://rapid.test.aaf.edu.au/jwt/authnrequest/research/Ag4EJJhjf0zXHqlKvKZEbg DF_AAF_AUTH_SIGNOUT_URL: https://sync-uat.deakin.edu.au/auth/logout diff --git a/nginx.conf b/nginx.conf index 3d38fa6fd5..679f2082fc 100644 --- a/nginx.conf +++ b/nginx.conf @@ -14,6 +14,10 @@ http { add_header Content-Security-Policy "default-src https: 'unsafe-inline' 'unsafe-eval' blob: data: ws:" always; # add_header Feature-Policy "microphone=(self),speaker=(self),fullscreen=(self),payment=(none);" always; add_header Permissions-Policy "microphone=(self),speaker=(self),fullscreen=(self),payment=(none)" always; + + location / { + try_files $uri $uri/ $uri/index.html /index.html; + } } gzip on; diff --git a/ngsw-config.json b/ngsw-config.json index a72a88ca4e..5c8069284f 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -46,5 +46,15 @@ ] } } + ], + "navigationUrls": [ + "/**", + "!/**/*.*", + "!/**/*__*", + "!/**/*__*/**", + "!/JPlag/**", + "!/JPlag", + "!/sidekiq/**", + "!/sidekiq" ] } diff --git a/package-lock.json b/package-lock.json index 4369004cc2..19291ceb8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.9", + "version": "10.0.1-22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.9", + "version": "10.0.1-22", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", @@ -16,28 +16,28 @@ "@angular/compiler": "^17.3.6", "@angular/core": "^17.3.6", "@angular/forms": "^17.3.6", - "@angular/material": "^17.3.6", - "@angular/material-moment-adapter": "^17.3.6", + "@angular/material": "^17.3.10", + "@angular/material-date-fns-adapter": "^17.3.10", "@angular/platform-browser": "^17.3.6", "@angular/platform-browser-dynamic": "^17.3.6", "@angular/router": "^17.3.6", "@angular/service-worker": "^17.3.6", "@angular/upgrade": "^17.3.6", - "@ctrl/ngx-emoji-mart": "^9.2.0", + "@ctrl/ngx-emoji-mart": "^9.3.0", "@ngneat/hotkeys": "^4.0.0", + "@ngstack/code-editor": "7.3.0", "@uirouter/angular": "^13.0", "@uirouter/angular-hybrid": "^17.1.0", "@uirouter/angularjs": "^1.0.30", "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", + "@worktile/gantt": "^18.0.5", "angular": "1.5.11", - "angular-cookies": "1.5.11", - "angular-file-upload": "~1", + "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", - "angular-local-storage": "0.7.1", "angular-markdown-filter": "1.3.2", "angular-md5": "0.1.10", - "angular-mocks": "1.5.11", + "angular-mocks": "1.8.3", "angular-nvd3": "1.0.9", "angular-resource": "1.5.11", "angular-sanitize": "1.5.11", @@ -52,23 +52,30 @@ "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", + "date-fns": "^3.6.0", "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", + "html2canvas": "^1.4.1", + "html5-qrcode": "^2.3.8", "jquery": "2.1.4", + "jszip": "^3.10.1", "lodash": "~4.17", - "lottie-web": "^5.12.2", + "lottie-web": "^5.13.0", "marked": "^11.1.0", "moment": "^2.29.4", + "monaco-editor": "^0.44.0", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", - "ng-flex-layout": "^17.3.4-beta.1", - "ng2-pdf-viewer": "^10.0", + "ng-flex-layout": "^17.3.7-beta.1", + "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.39", + "ngx-entity-service": "^0.0.41", "ngx-lottie": "^11.0.2", + "ngx-monaco-editor-v2": "^17.0.1", "nvd3": "1.8.6", - "rxjs": "~7.4.0", + "qrcode": "^1.5.4", + "rxjs": "~7.8.2", "ts-md5": "^1.3.1", "tslib": "^2.6.2", "underscore.string": "2.3.3", @@ -83,13 +90,13 @@ "@angular-eslint/template-parser": "^17.3.0", "@angular/compiler-cli": "^17.3.6", "@angular/language-service": "^17.3.6", - "@commitlint/cli": "^16.0.1", - "@commitlint/config-conventional": "^17", + "@commitlint/cli": "^20.5.0", + "@commitlint/config-conventional": "^20", "@types/angular": "1.5.11", "@types/canvas-confetti": "^1.6.0", "@types/d3": "^3.5.17", "@types/file-saver": "^2.0.1", - "@types/jasmine": "~3.9.1", + "@types/jasmine": "~6.0.0", "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", @@ -133,7 +140,7 @@ "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "load-grunt-tasks": "^5.0.0", - "npm-run-all": "^4.1.5", + "npm-run-all2": "^7.0", "postcss": "^8.4.27", "postcss-scss": "^0.1.7", "prettier": "^3.1.0", @@ -150,15 +157,17 @@ "optionalDependencies": { "@nx/nx-darwin-arm64": "^18.0", "@nx/nx-darwin-x64": "^18.0", + "@nx/nx-linux-arm64-gnu": "^18.0", "@nx/nx-linux-x64-gnu": "^18.0", - "@nx/nx-win32-x64-msvc": "^18.0" + "@nx/nx-win32-x64-msvc": "^18.0", + "@rollup/rollup-linux-arm64-gnu": "*", + "@rollup/rollup-linux-x64-gnu": "*" } }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -168,9 +177,8 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -180,11 +188,10 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1703.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.8.tgz", - "integrity": "sha512-lKxwG4/QABXZvJpqeSIn/kAwnY6MM9HdHZUV+o5o3UiTi+vO8rZApG4CCaITH3Bxebm7Nam7Xbk8RuukC5rq6g==", + "version": "0.1703.7", + "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.8", + "@angular-devkit/core": "17.3.7", "rxjs": "7.8.1" }, "engines": { @@ -195,22 +202,20 @@ }, "node_modules/@angular-devkit/architect/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.8.tgz", - "integrity": "sha512-ixsdXggWaFRP7Jvxd0AMukImnePuGflT9Yy7NJ9/y0cL/k//S/3RnkQv5i411KzN+7D4RIbNkRGGTYeqH24zlg==", + "version": "17.3.7", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1703.8", - "@angular-devkit/build-webpack": "0.1703.8", - "@angular-devkit/core": "17.3.8", + "@angular-devkit/architect": "0.1703.7", + "@angular-devkit/build-webpack": "0.1703.7", + "@angular-devkit/core": "17.3.7", "@babel/core": "7.24.0", "@babel/generator": "7.23.6", "@babel/helper-annotate-as-pure": "7.22.5", @@ -221,7 +226,7 @@ "@babel/preset-env": "7.24.0", "@babel/runtime": "7.24.0", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "17.3.8", + "@ngtools/webpack": "17.3.7", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.18", @@ -332,8 +337,6 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/autoprefixer": { "version": "10.4.18", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", - "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", "dev": true, "funding": [ { @@ -349,6 +352,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "browserslist": "^4.23.0", "caniuse-lite": "^1.0.30001591", @@ -369,8 +373,6 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/postcss": { "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -386,6 +388,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -397,24 +400,21 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular/node_modules/sass": { "version": "1.71.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", - "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -428,12 +428,11 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1703.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.8.tgz", - "integrity": "sha512-9u6fl8VVOxcLOEMzrUeaybSvi9hSLSRucHnybneYrabsgreDo32tuy/4G8p6YAHQjpWEj9jvF9Um13ertdni5Q==", + "version": "0.1703.7", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1703.8", + "@angular-devkit/architect": "0.1703.7", "rxjs": "7.8.1" }, "engines": { @@ -448,17 +447,15 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/core": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.8.tgz", - "integrity": "sha512-Q8q0voCGudbdCgJ7lXdnyaxKHbNQBARH68zPQV72WT8NWy+Gw/tys870i6L58NWbBaCJEUcIj/kb6KoakSRu+Q==", + "version": "17.3.7", + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -483,18 +480,16 @@ }, "node_modules/@angular-devkit/core/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/schematics": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.8.tgz", - "integrity": "sha512-QRVEYpIfgkprNHc916JlPuNbLzOgrm9DZalHasnLUz4P6g7pR21olb8YCyM2OTJjombNhya9ZpckcADU5Qyvlg==", + "version": "17.3.7", + "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.8", + "@angular-devkit/core": "17.3.7", "jsonc-parser": "3.2.1", "magic-string": "0.30.8", "ora": "5.4.1", @@ -508,20 +503,18 @@ }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-eslint/builder": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.5.2.tgz", - "integrity": "sha512-bvegxJuocWeHdvISPfCXeLQPSjrMCEVzxXPg16JJKksKWSeRA1JnbXnfnb7eoLdq1+riMHKqbH6Fs4rORAvUiA==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@nx/devkit": "^17.2.8 || ^18.0.0 || ^19.0.0", - "nx": "^17.2.8 || ^18.0.0 || ^19.0.0" + "@nx/devkit": "^17.2.8 || ^18.0.0", + "nx": "^17.2.8 || ^18.0.0" }, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -529,20 +522,18 @@ } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-17.5.2.tgz", - "integrity": "sha512-K4hVnMyI98faMJmsA4EOBkD0tapDjWV5gy0j/wJ2uSL46d3JgZPZNJSO1zStf/b3kT4gLOlQ/ulWFiUf1DxgIw==", - "dev": true + "version": "17.4.0", + "dev": true, + "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-17.5.2.tgz", - "integrity": "sha512-kzPALKyT5XIEbgoNmY/hEZWdMWKTX56Pap9fVLJSC/b+Nd+MXc7TNly2s0XoC0Ru1/kMiVzbmSGPheu/rw+9aA==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.2", - "@angular-eslint/utils": "17.5.2", - "@typescript-eslint/utils": "7.11.0" + "@angular-eslint/bundled-angular-compiler": "17.4.0", + "@angular-eslint/utils": "17.4.0", + "@typescript-eslint/utils": "7.8.0" }, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -550,15 +541,14 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-17.5.2.tgz", - "integrity": "sha512-6sxVwrJ7yElZxcjxHSA0Ujs29bCD/cMubd9n6TDFI9e3v+ktpoMW4Nv/TCHv0OuYatIOZ7bcJxi38cAO8Vhfhw==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.2", - "@angular-eslint/utils": "17.5.2", - "@typescript-eslint/type-utils": "7.11.0", - "@typescript-eslint/utils": "7.11.0", + "@angular-eslint/bundled-angular-compiler": "17.4.0", + "@angular-eslint/utils": "17.4.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "aria-query": "5.3.0", "axobject-query": "4.0.0" }, @@ -568,16 +558,15 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-17.5.2.tgz", - "integrity": "sha512-HcvqrBEJfYMTc+fZ6YdRkb+9YcXsy2XSv59Yhd0bBqZ4ZdM4QuuVFxWlLNvhV6TF1DtO24CzpN4OyE+AO5EWBA==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/eslint-plugin": "17.5.2", - "@angular-eslint/eslint-plugin-template": "17.5.2", - "@nx/devkit": "^17.2.8 || ^18.0.0 || ^19.0.0", + "@angular-eslint/eslint-plugin": "17.4.0", + "@angular-eslint/eslint-plugin-template": "17.4.0", + "@nx/devkit": "^17.2.8 || ^18.0.0", "ignore": "5.3.1", - "nx": "^17.2.8 || ^18.0.0 || ^19.0.0", + "nx": "^17.2.8 || ^18.0.0", "strip-json-comments": "3.1.1", "tmp": "0.2.3" }, @@ -586,12 +575,11 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-17.5.2.tgz", - "integrity": "sha512-46emLElmnIUzW0bpEpSf0u05ofRVUwlfttDOMLedhi700peUKbB9Y6iyz3GzAtQCMklBbJC9nR87LQRH9aSlog==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.2", + "@angular-eslint/bundled-angular-compiler": "17.4.0", "eslint-scope": "^8.0.0" }, "peerDependencies": { @@ -600,13 +588,12 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "17.5.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-17.5.2.tgz", - "integrity": "sha512-bTMPFqtoetBJsYR/xqREEOCy/CdsKGf2gZkRdH73gG6pOpskWt8J/PbRcMZsC349paV4HFixByVm89inqA0TNg==", + "version": "17.4.0", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.2", - "@typescript-eslint/utils": "7.11.0" + "@angular-eslint/bundled-angular-compiler": "17.4.0", + "@typescript-eslint/utils": "7.8.0" }, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -614,9 +601,8 @@ } }, "node_modules/@angular/animations": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.10.tgz", - "integrity": "sha512-9fR5snTuG4aM2K54TG/6DXcKXMDKZMovZhjQOxO8l68/oqn6fKrHs8DLzckFs0XGRZ+2OyURH8WggFm1Z828rA==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -624,7 +610,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.3.10" + "@angular/core": "17.3.8" } }, "node_modules/@angular/cdk": { @@ -644,14 +630,13 @@ } }, "node_modules/@angular/cli": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.8.tgz", - "integrity": "sha512-X5ZOQ6ZTKVHjhIsfl32ZRqbs+FUoeHLbT7x4fh2Os/8ObDDwrUcCJPqxe2b2RB5E2d0vepYigknHeLE7gwzlNQ==", + "version": "17.3.7", + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1703.8", - "@angular-devkit/core": "17.3.8", - "@angular-devkit/schematics": "17.3.8", - "@schematics/angular": "17.3.8", + "@angular-devkit/architect": "0.1703.7", + "@angular-devkit/core": "17.3.7", + "@angular-devkit/schematics": "17.3.7", + "@schematics/angular": "17.3.7", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.2", @@ -677,9 +662,8 @@ } }, "node_modules/@angular/common": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.10.tgz", - "integrity": "sha512-6SfD21M3LujymmZsZQIxAsV8Bj5u6He6ImZ+p2rr7FAhFxpVJyKldK8LCmJcFsBD4srpQcxEZ0iDxXvg+0ihAw==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -687,14 +671,13 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.3.10", + "@angular/core": "17.3.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.10.tgz", - "integrity": "sha512-6Ce4siHyF0fCZBDm/cz+blJByGDu1/hbPkQVGmk5HGZTmCUeKkgyjoM6bZr7ssAsyGDRwxBh2SGHO4Ce31vuPA==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -702,7 +685,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.3.10" + "@angular/core": "17.3.8" }, "peerDependenciesMeta": { "@angular/core": { @@ -711,10 +694,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.10.tgz", - "integrity": "sha512-85SBphqRj3szac3FbeYgEZ+I6WaAlo5h7JX06BdjOLLiaoIwlFhLeAuG+jVekseV+95grFUxIsCMphWHi2e6hQ==", + "version": "17.3.8", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "7.23.9", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -734,15 +716,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.3.10", + "@angular/compiler": "17.3.8", "typescript": ">=5.2 <5.5" } }, "node_modules/@angular/compiler-cli/node_modules/@babel/core": { "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -770,23 +751,20 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@angular/core": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.10.tgz", - "integrity": "sha512-ocEKu7X0yFCOvgJn1uZy76qjhsjKvULrO1k/BuIX0nwhp61DTGYTvCqKmwCBLM8/gvcKYH5vMKMHoQKtiSGE0A==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -799,9 +777,8 @@ } }, "node_modules/@angular/forms": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.10.tgz", - "integrity": "sha512-0VZWSXDi2M3DAGJlpdV3lo73Yo/73GPRqmfTOrvIoUIenFg5Dz6oNGzvt/1aRkRn6HKccjix6iMpH91EN65pWA==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -809,17 +786,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.3.10", - "@angular/core": "17.3.10", - "@angular/platform-browser": "17.3.10", + "@angular/common": "17.3.8", + "@angular/core": "17.3.8", + "@angular/platform-browser": "17.3.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-17.3.10.tgz", - "integrity": "sha512-6y0yEnjuKGCnH+YxmZZUC/KEb2ZuB5z7y0AOj4PwOladMWSwHv71x1rz5MokBVBf7ZTeN2w89f9jSWBzSz+fPw==", + "version": "17.3.8", "dev": true, + "license": "MIT", "engines": { "node": "^18.13.0 || >=20.9.0" } @@ -888,23 +864,22 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/material-moment-adapter": { + "node_modules/@angular/material-date-fns-adapter": { "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-17.3.10.tgz", - "integrity": "sha512-R68ssdGMSmVIfpOGaB9vjW5lBh6zH9GboBuaIAqizC/ZAzdEgpmT7qdr3PBCmRPTLTx8Yx9K3rhgRekO79ympw==", + "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-17.3.10.tgz", + "integrity": "sha512-Q4QAPGImZTjKW9ZhLSTkBeQX21I0dtak3JbexYx4CN/pHxKRpen6KaVAEqiORqq6vNUP2Kwb7cZznQyj6L7oQw==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "^17.0.0 || ^18.0.0", "@angular/material": "17.3.10", - "moment": "^2.18.1" + "date-fns": ">2.20.0 <4.0" } }, "node_modules/@angular/platform-browser": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.10.tgz", - "integrity": "sha512-LEhBDOKm2A7nRmZqsafVp6OinRDG1OYZBSqjnT1jZ+f0CRRFIXz6aJ0TMPoU6vq9SLRJ7vrGD9P/eBf2hW00NQ==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -912,9 +887,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/animations": "17.3.10", - "@angular/common": "17.3.10", - "@angular/core": "17.3.10" + "@angular/animations": "17.3.8", + "@angular/common": "17.3.8", + "@angular/core": "17.3.8" }, "peerDependenciesMeta": { "@angular/animations": { @@ -923,9 +898,8 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.10.tgz", - "integrity": "sha512-TW6G4+isdHM2ssQTRTobeAKtR2516pJ25BSwRb+9+Jw/ZAEYOOi+KQyofIFYQccaUjb3+LpjRcaZbtZ9m/Ispg==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -933,16 +907,15 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.3.10", - "@angular/compiler": "17.3.10", - "@angular/core": "17.3.10", - "@angular/platform-browser": "17.3.10" + "@angular/common": "17.3.8", + "@angular/compiler": "17.3.8", + "@angular/core": "17.3.8", + "@angular/platform-browser": "17.3.8" } }, "node_modules/@angular/router": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.10.tgz", - "integrity": "sha512-HlZlR9BOLoEKGOSMjmL5EfYL7F7PeDifbFi0dYWNcrG8zFrVKFklB1cuBdJhfPZgYhDEoGms/EToD71tg5wliA==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -950,16 +923,15 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.3.10", - "@angular/core": "17.3.10", - "@angular/platform-browser": "17.3.10", + "@angular/common": "17.3.8", + "@angular/core": "17.3.8", + "@angular/platform-browser": "17.3.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-17.3.10.tgz", - "integrity": "sha512-tRoO1WrA4TxLyQK4DFtant3R93DQuGs/DIvhYZ5Tpevaj8h/gL1Uwxzj3GAyZpMSbXvETlHAK8HcwG4IkXkxBg==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -970,14 +942,13 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.3.10", - "@angular/core": "17.3.10" + "@angular/common": "17.3.8", + "@angular/core": "17.3.8" } }, "node_modules/@angular/upgrade": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-17.3.10.tgz", - "integrity": "sha512-JAZxvMvZnbwdbFNzSsfAIxNOp/th7289BcJtq7cubdVfmFKajihLd1rt33cj+iFGUIy5SgSPmSvFVRQi7oSAaA==", + "version": "17.3.8", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -985,19 +956,18 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.3.10", - "@angular/core": "17.3.10", - "@angular/platform-browser": "17.3.10", - "@angular/platform-browser-dynamic": "17.3.10" + "@angular/compiler": "17.3.8", + "@angular/core": "17.3.8", + "@angular/platform-browser": "17.3.8", + "@angular/platform-browser-dynamic": "17.3.8" } }, "node_modules/@babel/code-frame": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", - "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "version": "7.24.2", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.6", + "@babel/highlight": "^7.24.2", "picocolors": "^1.0.0" }, "engines": { @@ -1005,19 +975,17 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", - "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==", + "version": "7.24.4", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -1045,24 +1013,21 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", @@ -1075,9 +1040,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1086,25 +1050,23 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.6.tgz", - "integrity": "sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==", + "version": "7.22.15", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", - "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", + "version": "7.23.6", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.6", - "@babel/helper-validator-option": "^7.24.6", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -1115,27 +1077,25 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", - "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", + "version": "7.24.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.24.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.24.5", "semver": "^6.3.1" }, "engines": { @@ -1145,25 +1105,12 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1171,20 +1118,18 @@ }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.6.tgz", - "integrity": "sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==", + "version": "7.22.15", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-annotate-as-pure": "^7.22.5", "regexpu-core": "^5.3.1", "semver": "^6.3.1" }, @@ -1195,32 +1140,18 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -1233,74 +1164,68 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", + "version": "7.22.20", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "version": "7.23.0", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", - "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", - "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", - "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "version": "7.24.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", - "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-module-imports": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1310,47 +1235,43 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", - "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", - "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", + "version": "7.24.5", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.6.tgz", - "integrity": "sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==", + "version": "7.22.20", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-wrap-function": "^7.24.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1359,27 +1280,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", - "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1389,24 +1297,22 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", - "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", - "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1414,9 +1320,8 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1425,66 +1330,61 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", - "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", + "version": "7.24.1", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", - "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", + "version": "7.24.5", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", - "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", + "version": "7.23.5", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz", - "integrity": "sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.6", - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/helper-function-name": "^7.23.0", + "@babel/template": "^7.24.0", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz", - "integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", - "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1494,10 +1394,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.5", "dev": true, + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -1506,12 +1405,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.6", - "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.24.6.tgz", - "integrity": "sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1521,14 +1419,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.6.tgz", - "integrity": "sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", - "@babel/plugin-transform-optional-chaining": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -1538,13 +1435,12 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.6.tgz", - "integrity": "sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1555,9 +1451,8 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -1567,9 +1462,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1579,9 +1473,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -1591,9 +1484,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1606,9 +1498,8 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1618,9 +1509,8 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -1629,12 +1519,11 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.6.tgz", - "integrity": "sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1644,12 +1533,11 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.6.tgz", - "integrity": "sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1660,9 +1548,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1672,9 +1559,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1684,9 +1570,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1696,9 +1581,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1708,9 +1592,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1720,9 +1603,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1732,9 +1614,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1744,9 +1625,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1756,9 +1636,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1771,9 +1650,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1786,9 +1664,8 @@ }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1801,12 +1678,11 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.6.tgz", - "integrity": "sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1817,9 +1693,8 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", - "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", @@ -1835,9 +1710,8 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", - "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", @@ -1851,12 +1725,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.6.tgz", - "integrity": "sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1866,12 +1739,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.6.tgz", - "integrity": "sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1881,13 +1753,12 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.6.tgz", - "integrity": "sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1897,13 +1768,12 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.6.tgz", - "integrity": "sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==", + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -1914,18 +1784,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.6.tgz", - "integrity": "sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", + "version": "7.24.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.24.5", "globals": "^11.1.0" }, "engines": { @@ -1935,38 +1804,24 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.6.tgz", - "integrity": "sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/template": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1976,12 +1831,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.6.tgz", - "integrity": "sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1991,13 +1845,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.6.tgz", - "integrity": "sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2007,12 +1860,11 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.6.tgz", - "integrity": "sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2022,12 +1874,11 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.6.tgz", - "integrity": "sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -2038,13 +1889,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.6.tgz", - "integrity": "sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2054,12 +1904,11 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.6.tgz", - "integrity": "sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -2070,13 +1919,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.6.tgz", - "integrity": "sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2086,14 +1934,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.6.tgz", - "integrity": "sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2103,12 +1950,11 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.6.tgz", - "integrity": "sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -2119,12 +1965,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.6.tgz", - "integrity": "sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2134,12 +1979,11 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.6.tgz", - "integrity": "sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -2150,12 +1994,11 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.6.tgz", - "integrity": "sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2165,13 +2008,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.6.tgz", - "integrity": "sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2181,14 +2023,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", - "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2198,15 +2039,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.6.tgz", - "integrity": "sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.6", - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -2216,13 +2056,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.6.tgz", - "integrity": "sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2232,13 +2071,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.6.tgz", - "integrity": "sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==", + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2248,12 +2086,11 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.6.tgz", - "integrity": "sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2263,12 +2100,11 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.6.tgz", - "integrity": "sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -2279,12 +2115,11 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.6.tgz", - "integrity": "sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -2295,15 +2130,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.6.tgz", - "integrity": "sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.6" + "@babel/plugin-transform-parameters": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2313,13 +2147,12 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.6.tgz", - "integrity": "sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2329,12 +2162,11 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.6.tgz", - "integrity": "sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -2345,13 +2177,12 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.6.tgz", - "integrity": "sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -2362,12 +2193,11 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz", - "integrity": "sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2377,13 +2207,12 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.6.tgz", - "integrity": "sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2393,14 +2222,13 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.6.tgz", - "integrity": "sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.5", + "@babel/helper-plugin-utils": "^7.24.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -2410,25 +2238,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.6.tgz", - "integrity": "sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2438,12 +2253,11 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.6.tgz", - "integrity": "sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.0", "regenerator-transform": "^0.15.2" }, "engines": { @@ -2454,12 +2268,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.6.tgz", - "integrity": "sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2470,9 +2283,8 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", - "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0", @@ -2490,20 +2302,18 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.6.tgz", - "integrity": "sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2513,13 +2323,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.6.tgz", - "integrity": "sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2529,12 +2338,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.6.tgz", - "integrity": "sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2544,12 +2352,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.6.tgz", - "integrity": "sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2559,12 +2366,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.6.tgz", - "integrity": "sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2574,12 +2380,11 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.6.tgz", - "integrity": "sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2589,13 +2394,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.6.tgz", - "integrity": "sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2605,13 +2409,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.6.tgz", - "integrity": "sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2621,13 +2424,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.6.tgz", - "integrity": "sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==", + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2638,9 +2440,8 @@ }, "node_modules/@babel/preset-env": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", - "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", @@ -2732,18 +2533,16 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2755,15 +2554,13 @@ }, "node_modules/@babel/regjsgen": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/runtime": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2772,33 +2569,31 @@ } }, "node_modules/@babel/template": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", - "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "version": "7.24.0", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz", - "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/generator": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-hoist-variables": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6", + "version": "7.24.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2807,12 +2602,11 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz", - "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -2822,25 +2616,23 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", - "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "version": "7.24.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2849,554 +2641,333 @@ }, "node_modules/@colors/colors": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/@commitlint/cli": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-16.3.0.tgz", - "integrity": "sha512-P+kvONlfsuTMnxSwWE1H+ZcPMY3STFaHb2kAacsqoIkNx66O0T7sTpBxpxkMrFPyhkJiLJnJWMhk4bbvYD3BMA==", - "dev": true, - "dependencies": { - "@commitlint/format": "^16.2.1", - "@commitlint/lint": "^16.2.4", - "@commitlint/load": "^16.3.0", - "@commitlint/read": "^16.2.1", - "@commitlint/types": "^16.2.1", - "lodash": "^4.17.19", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz", + "integrity": "sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^20.5.0", + "@commitlint/lint": "^20.5.0", + "@commitlint/load": "^20.5.0", + "@commitlint/read": "^20.5.0", + "@commitlint/types": "^20.5.0", + "tinyexec": "^1.0.0", "yargs": "^17.0.0" }, "bin": { "commitlint": "cli.js" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/config-conventional": { - "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.8.1.tgz", - "integrity": "sha512-NxCOHx1kgneig3VLauWJcDWS40DVjg7nKOpBEEK9E5fjJpQqLCilcnKkIIjdBH98kEO1q3NpE5NSrZ2kl/QGJg==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz", + "integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==", "dev": true, + "license": "MIT", "dependencies": { - "conventional-changelog-conventionalcommits": "^6.1.0" + "@commitlint/types": "^20.5.0", + "conventional-changelog-conventionalcommits": "^9.2.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/config-validator": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-16.2.1.tgz", - "integrity": "sha512-hogSe0WGg7CKmp4IfNbdNES3Rq3UEI4XRPB8JL4EPgo/ORq5nrGTVzxJh78omibNuB8Ho4501Czb1Er1MoDWpw==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.5.0.tgz", + "integrity": "sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^16.2.1", - "ajv": "^6.12.6" + "@commitlint/types": "^20.5.0", + "ajv": "^8.11.0" }, "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "node": ">=v18" } }, - "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/@commitlint/ensure": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-16.2.1.tgz", - "integrity": "sha512-/h+lBTgf1r5fhbDNHOViLuej38i3rZqTQnBTk+xEg+ehOwQDXUuissQ5GsYXXqI5uGy+261ew++sT4EA3uBJ+A==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.0.tgz", + "integrity": "sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^16.2.1", - "lodash": "^4.17.19" + "@commitlint/types": "^20.5.0", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/execute-rule": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-16.2.1.tgz", - "integrity": "sha512-oSls82fmUTLM6cl5V3epdVo4gHhbmBFvCvQGHBRdQ50H/690Uq1Dyd7hXMuKITCIdcnr9umyDkr8r5C6HZDF3g==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/format": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-16.2.1.tgz", - "integrity": "sha512-Yyio9bdHWmNDRlEJrxHKglamIk3d6hC0NkEUW6Ti6ipEh2g0BAhy8Od6t4vLhdZRa1I2n+gY13foy+tUgk0i1Q==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.5.0.tgz", + "integrity": "sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^16.2.1", - "chalk": "^4.0.0" + "@commitlint/types": "^20.5.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/format/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/@commitlint/is-ignored": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.5.0.tgz", + "integrity": "sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@commitlint/types": "^20.5.0", + "semver": "^7.6.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=v18" } }, - "node_modules/@commitlint/format/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/@commitlint/lint": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.0.tgz", + "integrity": "sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@commitlint/is-ignored": "^20.5.0", + "@commitlint/parse": "^20.5.0", + "@commitlint/rules": "^20.5.0", + "@commitlint/types": "^20.5.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=v18" } }, - "node_modules/@commitlint/format/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/@commitlint/load": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.0.tgz", + "integrity": "sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@commitlint/config-validator": "^20.5.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.5.0", + "@commitlint/types": "^20.5.0", + "cosmiconfig": "^9.0.1", + "cosmiconfig-typescript-loader": "^6.1.0", + "is-plain-obj": "^4.1.0", + "lodash.mergewith": "^4.6.2", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=v18" } }, - "node_modules/@commitlint/format/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@commitlint/load/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@commitlint/format/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/@commitlint/message": { + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.3.tgz", + "integrity": "sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/format/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/@commitlint/parse": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.5.0.tgz", + "integrity": "sha512-SeKWHBMk7YOTnnEWUhx+d1a9vHsjjuo6Uo1xRfPNfeY4bdYFasCH1dDpAv13Lyn+dDPOels+jP6D2GRZqzc5fA==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@commitlint/types": "^20.5.0", + "conventional-changelog-angular": "^8.2.0", + "conventional-commits-parser": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored": { - "version": "16.2.4", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-16.2.4.tgz", - "integrity": "sha512-Lxdq9aOAYCOOOjKi58ulbwK/oBiiKz+7Sq0+/SpFIEFwhHkIVugvDvWjh2VRBXmRC/x5lNcjDcYEwS/uYUvlYQ==", + "node_modules/@commitlint/read": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.5.0.tgz", + "integrity": "sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^16.2.1", - "semver": "7.3.7" + "@commitlint/top-level": "^20.4.3", + "@commitlint/types": "^20.5.0", + "git-raw-commits": "^5.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@commitlint/resolve-extends": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.0.tgz", + "integrity": "sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@commitlint/config-validator": "^20.5.0", + "@commitlint/types": "^20.5.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "node_modules/@commitlint/rules": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.0.tgz", + "integrity": "sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@commitlint/ensure": "^20.5.0", + "@commitlint/message": "^20.4.3", + "@commitlint/to-lines": "^20.0.0", + "@commitlint/types": "^20.5.0" }, "engines": { - "node": ">=10" + "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@commitlint/lint": { - "version": "16.2.4", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-16.2.4.tgz", - "integrity": "sha512-AUDuwOxb2eGqsXbTMON3imUGkc1jRdtXrbbohiLSCSk3jFVXgJLTMaEcr39pR00N8nE9uZ+V2sYaiILByZVmxQ==", + "node_modules/@commitlint/to-lines": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz", + "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==", "dev": true, - "dependencies": { - "@commitlint/is-ignored": "^16.2.4", - "@commitlint/parse": "^16.2.1", - "@commitlint/rules": "^16.2.4", - "@commitlint/types": "^16.2.1" - }, + "license": "MIT", "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/load": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-16.3.0.tgz", - "integrity": "sha512-3tykjV/iwbkv2FU9DG+NZ/JqmP0Nm3b7aDwgCNQhhKV5P74JAuByULkafnhn+zsFGypG1qMtI5u+BZoa9APm0A==", + "node_modules/@commitlint/top-level": { + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.3.tgz", + "integrity": "sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^16.2.1", - "@commitlint/execute-rule": "^16.2.1", - "@commitlint/resolve-extends": "^16.2.1", - "@commitlint/types": "^16.2.1", - "@types/node": ">=12", - "chalk": "^4.0.0", - "cosmiconfig": "^7.0.0", - "cosmiconfig-typescript-loader": "^2.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "typescript": "^4.4.3" + "escalade": "^3.2.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/load/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/@commitlint/types": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.5.0.tgz", + "integrity": "sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "conventional-commits-parser": "^6.3.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=v18" } }, - "node_modules/@commitlint/load/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/@conventional-changelog/git-client": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz", + "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@simple-libs/child-process-utils": "^1.0.0", + "@simple-libs/stream-utils": "^1.2.0", + "semver": "^7.5.2" }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.3.0" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } } }, - "node_modules/@commitlint/load/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/@cspotcode/source-map-support": { + "version": "0.8.1", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/@commitlint/load/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@commitlint/load/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/@commitlint/message": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.2.1.tgz", - "integrity": "sha512-2eWX/47rftViYg7a3axYDdrgwKv32mxbycBJT6OQY/MJM7SUfYNYYvbMFOQFaA4xIVZt7t2Alyqslbl6blVwWw==", - "dev": true, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/parse": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-16.2.1.tgz", - "integrity": "sha512-2NP2dDQNL378VZYioLrgGVZhWdnJO4nAxQl5LXwYb08nEcN+cgxHN1dJV8OLJ5uxlGJtDeR8UZZ1mnQ1gSAD/g==", - "dev": true, - "dependencies": { - "@commitlint/types": "^16.2.1", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.2.2" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/read": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-16.2.1.tgz", - "integrity": "sha512-tViXGuaxLTrw2r7PiYMQOFA2fueZxnnt0lkOWqKyxT+n2XdEMGYcI9ID5ndJKXnfPGPppD0w/IItKsIXlZ+alw==", - "dev": true, - "dependencies": { - "@commitlint/top-level": "^16.2.1", - "@commitlint/types": "^16.2.1", - "fs-extra": "^10.0.0", - "git-raw-commits": "^2.0.0" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/resolve-extends": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-16.2.1.tgz", - "integrity": "sha512-NbbCMPKTFf2J805kwfP9EO+vV+XvnaHRcBy6ud5dF35dxMsvdJqke54W3XazXF1ZAxC4a3LBy4i/GNVBAthsEg==", - "dev": true, - "dependencies": { - "@commitlint/config-validator": "^16.2.1", - "@commitlint/types": "^16.2.1", - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/rules": { - "version": "16.2.4", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-16.2.4.tgz", - "integrity": "sha512-rK5rNBIN2ZQNQK+I6trRPK3dWa0MtaTN4xnwOma1qxa4d5wQMQJtScwTZjTJeallFxhOgbNOgr48AMHkdounVg==", - "dev": true, - "dependencies": { - "@commitlint/ensure": "^16.2.1", - "@commitlint/message": "^16.2.1", - "@commitlint/to-lines": "^16.2.1", - "@commitlint/types": "^16.2.1", - "execa": "^5.0.0" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/to-lines": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-16.2.1.tgz", - "integrity": "sha512-9/VjpYj5j1QeY3eiog1zQWY6axsdWAc0AonUUfyZ7B0MVcRI0R56YsHAfzF6uK/g/WwPZaoe4Lb1QCyDVnpVaQ==", - "dev": true, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/top-level": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-16.2.1.tgz", - "integrity": "sha512-lS6GSieHW9y6ePL73ied71Z9bOKyK+Ib9hTkRsB8oZFAyQZcyRwq2w6nIa6Fngir1QW51oKzzaXfJL94qwImyw==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/types": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-16.2.1.tgz", - "integrity": "sha512-7/z7pA7BM0i8XvMSBynO7xsB3mVQPUZbVn6zMIlp/a091XJ3qAXRXc+HwLYhiIdzzS5fuxxNIHZMGHVD4HJxdA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@commitlint/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@commitlint/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@commitlint/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@commitlint/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@ctrl/ngx-emoji-mart": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@ctrl/ngx-emoji-mart/-/ngx-emoji-mart-9.2.0.tgz", - "integrity": "sha512-q8B7DiXPfyTe+VOGO6Ix7eh5gKCuADxAsud2xXRTlECTfchoKGTmirSczyjaxIKE/xmB+/ZsnkpthZqUM7SAJQ==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@ctrl/ngx-emoji-mart/-/ngx-emoji-mart-9.3.0.tgz", + "integrity": "sha512-9uFzAvlFT21OLsTfhL3ZEO5mp51qvL1F4ErIZVBIsvAlji46u6p2KGgVA60oIheFBX4JoZI7HBDGOkGnm9dTUQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3406,18 +2977,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@es-joy/jsdoccomment": { "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz", - "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==", "dev": true, + "license": "MIT", "dependencies": { "comment-parser": "1.3.1", "esquery": "^1.4.0", @@ -3571,22 +3140,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", - "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-ia32": { "version": "0.20.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", @@ -3797,9 +3350,8 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -3811,19 +3363,17 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.10.0", "dev": true, + "license": "MIT", "engines": { "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==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3844,9 +3394,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3860,15 +3409,13 @@ }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "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" @@ -3876,9 +3423,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -3891,9 +3437,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3903,15 +3448,13 @@ }, "node_modules/@eslint/eslintrc/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/@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" }, @@ -3921,9 +3464,8 @@ }, "node_modules/@eslint/eslintrc/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, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3933,18 +3475,16 @@ }, "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, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.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==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", "debug": "^4.3.1", @@ -3956,9 +3496,8 @@ }, "node_modules/@humanwhocodes/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" @@ -3966,9 +3505,8 @@ }, "node_modules/@humanwhocodes/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" }, @@ -3978,9 +3516,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -3991,14 +3528,12 @@ }, "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==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -4013,8 +3548,7 @@ }, "node_modules/@isaacs/cliui/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==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -4024,8 +3558,7 @@ }, "node_modules/@isaacs/cliui/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==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -4035,13 +3568,11 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -4056,8 +3587,7 @@ }, "node_modules/@isaacs/cliui/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==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -4070,8 +3600,7 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -4086,9 +3615,8 @@ }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -4102,9 +3630,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4115,9 +3642,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -4127,9 +3653,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -4142,9 +3667,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -4154,18 +3678,16 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/schemas": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -4175,9 +3697,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -4189,27 +3710,24 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -4217,14 +3735,12 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -4232,14 +3748,12 @@ }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@ljharb/through": { "version": "2.3.13", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", - "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -4251,6 +3765,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", "optional": true, "dependencies": { "detect-libc": "^2.0.0", @@ -4271,6 +3786,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "optional": true, "dependencies": { "debug": "4" @@ -4283,6 +3799,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "optional": true, "dependencies": { "agent-base": "6", @@ -4296,6 +3813,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", "optional": true, "dependencies": { "semver": "^6.0.0" @@ -4311,6 +3829,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "optional": true, "bin": { "semver": "bin/semver.js" @@ -4320,6 +3839,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", "optional": true, "dependencies": { "abbrev": "1" @@ -4333,16 +3853,14 @@ }, "node_modules/@material/animation": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-1GSJaPKef+7HRuV+HusVZHps64cmZuOItDbt40tjJVaikcaZvwmHlcTxRIqzcRoCdt5ZKHh3NoO7GB9Khg4Jnw==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/auto-init": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-t7ZGpRJ3ec0QDUO0nJu/SMgLW7qcuG2KqIsEYD1Ej8qhI2xpdR2ydSDQOkVEitXmKoGol1oq4nYSBjTlB65GqA==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "tslib": "^2.1.0" @@ -4350,8 +3868,7 @@ }, "node_modules/@material/banner": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-g9wBUZzYBizyBcBQXTIafnRUUPi7efU9gPJfzeGgkynXiccP/vh5XMmH+PBxl5v+4MlP/d4cZ2NUYoAN7UTqSA==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/button": "15.0.0-canary.7f224ddd4.0", @@ -4369,16 +3886,14 @@ }, "node_modules/@material/base": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-I9KQOKXpLfJkP8MqZyr8wZIzdPHrwPjFvGd9zSK91/vPyE4hzHRJc/0njsh9g8Lm9PRYLbifXX+719uTbHxx+A==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/button": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-BHB7iyHgRVH+JF16+iscR+Qaic+p7LU1FOLgP8KucRlpF9tTwIxQA6mJwGRi5gUtcG+vyCmzVS+hIQ6DqT/7BA==", + "license": "MIT", "dependencies": { "@material/density": "15.0.0-canary.7f224ddd4.0", "@material/dom": "15.0.0-canary.7f224ddd4.0", @@ -4397,8 +3912,7 @@ }, "node_modules/@material/card": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-kt7y9/IWOtJTr3Z/AoWJT3ZLN7CLlzXhx2udCLP9ootZU2bfGK0lzNwmo80bv/pJfrY9ihQKCtuGTtNxUy+vIw==", + "license": "MIT", "dependencies": { "@material/dom": "15.0.0-canary.7f224ddd4.0", "@material/elevation": "15.0.0-canary.7f224ddd4.0", @@ -4413,8 +3927,7 @@ }, "node_modules/@material/checkbox": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-rURcrL5O1u6hzWR+dNgiQ/n89vk6tdmdP3mZgnxJx61q4I/k1yijKqNJSLrkXH7Rto3bM5NRKMOlgvMvVd7UMQ==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4431,8 +3944,7 @@ }, "node_modules/@material/chips": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-AYAivV3GSk/T/nRIpH27sOHFPaSMrE3L0WYbnb5Wa93FgY8a0fbsFYtSH2QmtwnzXveg+B1zGTt7/xIIcynKdQ==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4455,8 +3967,7 @@ }, "node_modules/@material/circular-progress": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-DJrqCKb+LuGtjNvKl8XigvyK02y36GRkfhMUYTcJEi3PrOE00bwXtyj7ilhzEVshQiXg6AHGWXtf5UqwNrx3Ow==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4470,8 +3981,7 @@ }, "node_modules/@material/data-table": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-/2WZsuBIq9z9RWYF5Jo6b7P6u0fwit+29/mN7rmAZ6akqUR54nXyNfoSNiyydMkzPlZZsep5KrSHododDhBZbA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4496,16 +4006,14 @@ }, "node_modules/@material/density": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-o9EXmGKVpiQ6mHhyV3oDDzc78Ow3E7v8dlaOhgaDSXgmqaE8v5sIlLNa/LKSyUga83/fpGk3QViSGXotpQx0jA==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/dialog": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-u0XpTlv1JqWC/bQ3DavJ1JguofTelLT2wloj59l3/1b60jv42JQ6Am7jU3I8/SIUB1MKaW7dYocXjDWtWJakLA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4526,8 +4034,7 @@ }, "node_modules/@material/dom": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-mQ1HT186GPQSkRg5S18i70typ5ZytfjL09R0gJ2Qg5/G+MLCGi7TAjZZSH65tuD/QGOjel4rDdWOTmYbPYV6HA==", + "license": "MIT", "dependencies": { "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", "@material/rtl": "15.0.0-canary.7f224ddd4.0", @@ -4536,8 +4043,7 @@ }, "node_modules/@material/drawer": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-qyO0W0KBftfH8dlLR0gVAgv7ZHNvU8ae11Ao6zJif/YxcvK4+gph1z8AO4H410YmC2kZiwpSKyxM1iQCCzbb4g==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4555,8 +4061,7 @@ }, "node_modules/@material/elevation": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-tV6s4/pUBECedaI36Yj18KmRCk1vfue/JP/5yYRlFNnLMRVISePbZaKkn/BHXVf+26I3W879+XqIGlDVdmOoMA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4568,8 +4073,7 @@ }, "node_modules/@material/fab": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-4h76QrzfZTcPdd+awDPZ4Q0YdSqsXQnS540TPtyXUJ/5G99V6VwGpjMPIxAsW0y+pmI9UkLL/srrMaJec+7r4Q==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/dom": "15.0.0-canary.7f224ddd4.0", @@ -4588,16 +4092,14 @@ }, "node_modules/@material/feature-targeting": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-SAjtxYh6YlKZriU83diDEQ7jNSP2MnxKsER0TvFeyG1vX/DWsUyYDOIJTOEa9K1N+fgJEBkNK8hY55QhQaspew==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/floating-label": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-0KMo5ijjYaEHPiZ2pCVIcbaTS2LycvH9zEhEMKwPPGssBCX7iz5ffYQFk7e5yrQand1r3jnQQgYfHAwtykArnQ==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4611,8 +4113,7 @@ }, "node_modules/@material/focus-ring": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-Jmg1nltq4J6S6A10EGMZnvufrvU3YTi+8R8ZD9lkSbun0Fm2TVdICQt/Auyi6An9zP66oQN6c31eqO6KfIPsDg==", + "license": "MIT", "dependencies": { "@material/dom": "15.0.0-canary.7f224ddd4.0", "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", @@ -4621,8 +4122,7 @@ }, "node_modules/@material/form-field": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-fEPWgDQEPJ6WF7hNnIStxucHR9LE4DoDSMqCsGWS2Yu+NLZYLuCEecgR0UqQsl1EQdNRaFh8VH93KuxGd2hiPg==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", @@ -4635,8 +4135,7 @@ }, "node_modules/@material/icon-button": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-DcK7IL4ICY/DW+48YQZZs9g0U1kRaW0Wb0BxhvppDMYziHo/CTpFdle4gjyuTyRxPOdHQz5a97ru48Z9O4muTw==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/density": "15.0.0-canary.7f224ddd4.0", @@ -4653,8 +4152,7 @@ }, "node_modules/@material/image-list": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-voMjG2p80XbjL1B2lmF65zO5gEgJOVKClLdqh4wbYzYfwY/SR9c8eLvlYG7DLdFaFBl/7gGxD8TvvZ329HUFPw==", + "license": "MIT", "dependencies": { "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", "@material/shape": "15.0.0-canary.7f224ddd4.0", @@ -4665,16 +4163,14 @@ }, "node_modules/@material/layout-grid": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-veDABLxMn2RmvfnUO2RUmC1OFfWr4cU+MrxKPoDD2hl3l3eDYv5fxws6r5T1JoSyXoaN+oEZpheS0+M9Ure8Pg==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/line-ripple": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-f60hVJhIU6I3/17Tqqzch1emUKEcfVVgHVqADbU14JD+oEIz429ZX9ksZ3VChoU3+eejFl+jVdZMLE/LrAuwpg==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4685,8 +4181,7 @@ }, "node_modules/@material/linear-progress": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-pRDEwPQielDiC9Sc5XhCXrGxP8wWOnAO8sQlMebfBYHYqy5hhiIzibezS8CSaW4MFQFyXmCmpmqWlbqGYRmiyg==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4700,8 +4195,7 @@ }, "node_modules/@material/list": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-Is0NV91sJlXF5pOebYAtWLF4wU2MJDbYqztML/zQNENkQxDOvEXu3nWNb3YScMIYJJXvARO0Liur5K4yPagS1Q==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/density": "15.0.0-canary.7f224ddd4.0", @@ -4718,8 +4212,7 @@ }, "node_modules/@material/menu": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-D11QU1dXqLbh5X1zKlEhS3QWh0b5BPNXlafc5MXfkdJHhOiieb7LC9hMJhbrHtj24FadJ7evaFW/T2ugJbJNnQ==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/dom": "15.0.0-canary.7f224ddd4.0", @@ -4737,8 +4230,7 @@ }, "node_modules/@material/menu-surface": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-7RZHvw0gbwppaAJ/Oh5SWmfAKJ62aw1IMB3+3MRwsb5PLoV666wInYa+zJfE4i7qBeOn904xqT2Nko5hY0ssrg==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4752,8 +4244,7 @@ }, "node_modules/@material/notched-outline": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-Yg2usuKB2DKlKIBISbie9BFsOVuffF71xjbxPbybvqemxqUBd+bD5/t6H1fLE+F8/NCu5JMigho4ewUU+0RCiw==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", @@ -4766,16 +4257,14 @@ }, "node_modules/@material/progress-indicator": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-UPbDjE5CqT+SqTs0mNFG6uFEw7wBlgYmh+noSkQ6ty/EURm8lF125dmi4dv4kW0+octonMXqkGtAoZwLIHKf/w==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/radio": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-wR1X0Sr0KmQLu6+YOFKAI84G3L6psqd7Kys5kfb8WKBM36zxO5HQXC5nJm/Y0rdn22ixzsIz2GBo0MNU4V4k1A==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4791,8 +4280,7 @@ }, "node_modules/@material/ripple": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-JqOsWM1f4aGdotP0rh1vZlPZTg6lZgh39FIYHFMfOwfhR+LAikUJ+37ciqZuewgzXB6iiRO6a8aUH6HR5SJYPg==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4805,8 +4293,7 @@ }, "node_modules/@material/rtl": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-UVf14qAtmPiaaZjuJtmN36HETyoKWmsZM/qn1L5ciR2URb8O035dFWnz4ZWFMmAYBno/L7JiZaCkPurv2ZNrGA==", + "license": "MIT", "dependencies": { "@material/theme": "15.0.0-canary.7f224ddd4.0", "tslib": "^2.1.0" @@ -4814,8 +4301,7 @@ }, "node_modules/@material/segmented-button": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-LCnVRUSAhELTKI/9hSvyvIvQIpPpqF29BV+O9yM4WoNNmNWqTulvuiv7grHZl6Z+kJuxSg4BGbsPxxb9dXozPg==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/elevation": "15.0.0-canary.7f224ddd4.0", @@ -4829,8 +4315,7 @@ }, "node_modules/@material/select": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-WioZtQEXRpglum0cMSzSqocnhsGRr+ZIhvKb3FlaNrTaK8H3Y4QA7rVjv3emRtrLOOjaT6/RiIaUMTo9AGzWQQ==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4855,8 +4340,7 @@ }, "node_modules/@material/shape": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-8z8l1W3+cymObunJoRhwFPKZ+FyECfJ4MJykNiaZq7XJFZkV6xNmqAVrrbQj93FtLsECn9g4PjjIomguVn/OEw==", + "license": "MIT", "dependencies": { "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", "@material/rtl": "15.0.0-canary.7f224ddd4.0", @@ -4866,8 +4350,7 @@ }, "node_modules/@material/slider": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-QU/WSaSWlLKQRqOhJrPgm29wqvvzRusMqwAcrCh1JTrCl+xwJ43q5WLDfjYhubeKtrEEgGu9tekkAiYfMG7EBw==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4884,8 +4367,7 @@ }, "node_modules/@material/snackbar": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-sm7EbVKddaXpT/aXAYBdPoN0k8yeg9+dprgBUkrdqGzWJAeCkxb4fv2B3He88YiCtvkTz2KLY4CThPQBSEsMFQ==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4905,8 +4387,7 @@ }, "node_modules/@material/switch": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-lEDJfRvkVyyeHWIBfoxYjJVl+WlEAE2kZ/+6OqB1FW0OV8ftTODZGhHRSzjVBA1/p4FPuhAtKtoK9jTpa4AZjA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4926,8 +4407,7 @@ }, "node_modules/@material/tab": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-E1xGACImyCLurhnizyOTCgOiVezce4HlBFAI6YhJo/AyVwjN2Dtas4ZLQMvvWWqpyhITNkeYdOchwCC1mrz3AQ==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/elevation": "15.0.0-canary.7f224ddd4.0", @@ -4944,8 +4424,7 @@ }, "node_modules/@material/tab-bar": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-p1Asb2NzrcECvAQU3b2SYrpyJGyJLQWR+nXTYzDKE8WOpLIRCXap2audNqD7fvN/A20UJ1J8U01ptrvCkwJ4eA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4963,8 +4442,7 @@ }, "node_modules/@material/tab-indicator": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-h9Td3MPqbs33spcPS7ecByRHraYgU4tNCZpZzZXw31RypjKvISDv/PS5wcA4RmWqNGih78T7xg4QIGsZg4Pk4w==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4975,8 +4453,7 @@ }, "node_modules/@material/tab-scroller": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-LFeYNjQpdXecwECd8UaqHYbhscDCwhGln5Yh+3ctvcEgvmDPNjhKn/DL3sWprWvG8NAhP6sHMrsGhQFVdCWtTg==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -4988,8 +4465,7 @@ }, "node_modules/@material/textfield": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-AExmFvgE5nNF0UA4l2cSzPghtxSUQeeoyRjFLHLy+oAaE4eKZFrSy0zEpqPeWPQpEMDZk+6Y+6T3cOFYBeSvsw==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -5010,8 +4486,7 @@ }, "node_modules/@material/theme": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-hs45hJoE9yVnoVOcsN1jklyOa51U4lzWsEnQEuJTPOk2+0HqCQ0yv/q0InpSnm2i69fNSyZC60+8HADZGF8ugQ==", + "license": "MIT", "dependencies": { "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", "tslib": "^2.1.0" @@ -5019,16 +4494,14 @@ }, "node_modules/@material/tokens": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-r9TDoicmcT7FhUXC4eYMFnt9TZsz0G8T3wXvkKncLppYvZ517gPyD/1+yhuGfGOxAzxTrM66S/oEc1fFE2q4hw==", + "license": "MIT", "dependencies": { "@material/elevation": "15.0.0-canary.7f224ddd4.0" } }, "node_modules/@material/tooltip": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-8qNk3pmPLTnam3XYC1sZuplQXW9xLn4Z4MI3D+U17Q7pfNZfoOugGr+d2cLA9yWAEjVJYB0mj8Yu86+udo4N9w==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -5047,8 +4520,7 @@ }, "node_modules/@material/top-app-bar": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-SARR5/ClYT4CLe9qAXakbr0i0cMY0V3V4pe3ElIJPfL2Z2c4wGR1mTR8m2LxU1MfGKK8aRoUdtfKaxWejp+eNA==", + "license": "MIT", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/base": "15.0.0-canary.7f224ddd4.0", @@ -5063,8 +4535,7 @@ }, "node_modules/@material/touch-target": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-BJo/wFKHPYLGsRaIpd7vsQwKr02LtO2e89Psv0on/p0OephlNIgeB9dD9W+bQmaeZsZ6liKSKRl6wJWDiK71PA==", + "license": "MIT", "dependencies": { "@material/base": "15.0.0-canary.7f224ddd4.0", "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", @@ -5075,27 +4546,43 @@ }, "node_modules/@material/typography": { "version": "15.0.0-canary.7f224ddd4.0", - "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.7f224ddd4.0.tgz", - "integrity": "sha512-kBaZeCGD50iq1DeRRH5OM5Jl7Gdk+/NOfKArkY4ksBZvJiStJ7ACAhpvb8MEGm4s3jvDInQFLsDq3hL+SA79sQ==", + "license": "MIT", "dependencies": { "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", "@material/theme": "15.0.0-canary.7f224ddd4.0", "tslib": "^2.1.0" } }, + "node_modules/@mattlewis92/dom-autoscroller": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", + "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", + "license": "MIT" + }, "node_modules/@ngneat/hotkeys": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@ngneat/hotkeys/-/hotkeys-4.0.0.tgz", - "integrity": "sha512-My5PVywrIVJDMD2j00O5hvW/70SmBwvz85v46WiJct5zyrxzQjSRh9ZD5SLH+LLEcjpiCFwCtpBD1RatzRlisQ==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" } }, + "node_modules/@ngstack/code-editor": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@ngstack/code-editor/-/code-editor-7.3.0.tgz", + "integrity": "sha512-ZqjRynFAA74sVGF5bHecwjXQf5vOM7+bkCd++mNlVGjCq6qVY0TtM7+9pCiCIvzVBn3++9KNDhlpDSq1m5WIYA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.5.0" + }, + "peerDependencies": { + "@angular/common": ">=17.1.1", + "@angular/core": ">=17.1.1" + } + }, "node_modules/@ngtools/webpack": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.8.tgz", - "integrity": "sha512-CjSVVa/9fzMpEDQP01SC4colKCbZwj7vUq0H2bivp8jVsmd21x9Fu0gDBH0Y9NdfAIm4eGZvmiZKMII3vIOaYQ==", + "version": "17.3.7", "dev": true, + "license": "MIT", "engines": { "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -5109,9 +4596,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -5122,18 +4608,16 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -5144,8 +4628,7 @@ }, "node_modules/@npmcli/agent": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -5159,16 +4642,14 @@ }, "node_modules/@npmcli/agent/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/@npmcli/fs": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -5178,8 +4659,7 @@ }, "node_modules/@npmcli/git": { "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", - "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "lru-cache": "^10.0.1", @@ -5196,32 +4676,28 @@ }, "node_modules/@npmcli/git/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", "engines": { "node": ">=16" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/@npmcli/git/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -5234,8 +4710,7 @@ }, "node_modules/@npmcli/installed-package-contents": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", - "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "license": "ISC", "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -5249,16 +4724,14 @@ }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/package-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", - "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "version": "5.1.0", + "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", @@ -5273,15 +4746,14 @@ } }, "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.3.15", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -5295,8 +4767,7 @@ }, "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -5306,30 +4777,14 @@ }, "node_modules/@npmcli/package-json/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, - "node_modules/@npmcli/package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@npmcli/package-json/node_modules/normalize-package-data": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", - "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", "is-core-module": "^2.8.1", @@ -5342,16 +4797,14 @@ }, "node_modules/@npmcli/package-json/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/promise-spawn": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", - "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "license": "ISC", "dependencies": { "which": "^4.0.0" }, @@ -5361,16 +4814,14 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", "engines": { "node": ">=16" } }, "node_modules/@npmcli/promise-spawn/node_modules/which": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -5383,16 +4834,14 @@ }, "node_modules/@npmcli/redact": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", - "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "license": "ISC", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@npmcli/run-script": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", - "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", @@ -5406,16 +4855,14 @@ }, "node_modules/@npmcli/run-script/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", "engines": { "node": ">=16" } }, "node_modules/@npmcli/run-script/node_modules/which": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -5427,21 +4874,19 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.1.2.tgz", - "integrity": "sha512-vWI+OrTICE9Yw6C/jIwxybnvavI9dnQJ7tpzFbLcSVfFAGdFtYJGCLVe40IkWcvUfELoVmzpXtKP/sPy0D7J9w==", + "version": "18.3.4", "dev": true, + "license": "MIT", "dependencies": { - "@nx/devkit": "19.1.2" + "@nx/devkit": "18.3.4" } }, "node_modules/@nrwl/tao": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.1.2.tgz", - "integrity": "sha512-OseWzHXNwOmZinUjHCD+edinvNJq5ngGrn/yKO81Zm/FDxkcYjud20dMsXi8zYfgDjvQv22eDtk5v1BTlSx57A==", + "version": "18.3.4", "dev": true, + "license": "MIT", "dependencies": { - "nx": "19.1.2", + "nx": "18.3.4", "tslib": "^2.3.0" }, "bin": { @@ -5449,23 +4894,21 @@ } }, "node_modules/@nx/devkit": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.1.2.tgz", - "integrity": "sha512-oHYZzfmvogPh7z8pf1RjW7eJaS05VZ1Ts/axlWerzQauWT7aoeyCaxa0D9q3ThnUuDt1PqKjwJi5jmCihBT2Sw==", + "version": "18.3.4", "dev": true, + "license": "MIT", "dependencies": { - "@nrwl/devkit": "19.1.2", + "@nrwl/devkit": "18.3.4", "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" + "nx": ">= 16 <= 19" } }, "node_modules/@nx/nx-darwin-arm64": { @@ -5499,9 +4942,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.1.2.tgz", - "integrity": "sha512-0wcBAr+IYOWBXNDdWHahjW1nCyFTP0O+dSsQa5ab5OBEo0UTvt1k/s27cUyaz2Ll070RTpzl54KD3O1i/1/X0Q==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.3.4.tgz", + "integrity": "sha512-bjSPak/d+bcR95/pxHMRhnnpHc6MnrQcG6f5AjX15Esm4JdrdQKPBmG1RybuK0WKSyD5wgVhkAGc/QQUom9l8g==", "cpu": [ "x64" ], @@ -5515,9 +4958,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.1.2.tgz", - "integrity": "sha512-A1L7T/Y8nOq7tc84WuaWMEeZ2uTjhqHJDNEfgZhnwYfQ3S94B0O2EkyEp29n9E4eN9XZmvYJzDt1tBz2ziZ6iA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.3.4.tgz", + "integrity": "sha512-/1HnUL7jhH0S7PxJqf6R1pk3QlAU22GY89EQV9fd+RDUtp7IyzaTlkebijTIqfxlSjC4OO3bPizaxEaxdd3uKQ==", "cpu": [ "arm" ], @@ -5531,13 +4974,12 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.1.2.tgz", - "integrity": "sha512-ze7FtI0hGMs6ap9Z8vo80nXMvuJGJP7CDcL8q2op/l9c23Qex+oG4khyZowJzq+fJPigqldAL3Fm+rHBzT4jhA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.3.4.tgz", + "integrity": "sha512-g/2IaB2bZTKaBNPEf9LxtIXb1XHdhh3VO9PnePIrwkkixPMLN0dTxT5Sttt75lvLP3EU1AUR5w3Aaz2Q1mYtWA==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5547,9 +4989,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.1.2.tgz", - "integrity": "sha512-JMiSRLe3K83GQw26jGgJYCLDww7K4z5rVDlWHpQEMyiQSukJBZ5OMYxotkDcPDAMmmrUERXjabOsCi0xnyqUlA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.3.4.tgz", + "integrity": "sha512-MgfKLoEF6I1cCS+0ooFLEjJSSVdCYyCT9Q96IHRJntAEL8u/0GR2OUoBoLC+q1lnbIkJr/uqTJxA2Jh+sJTIbA==", "cpu": [ "arm64" ], @@ -5578,9 +5020,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.1.2.tgz", - "integrity": "sha512-tID0nKIUQZ5b1woFh3dtl7XK1Mv71kkwxxppMsOb0FVTigC8Yy7Zpu/ykKidnJ+VbHGSYhZ03BZXgAk/on9LXw==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.3.4.tgz", + "integrity": "sha512-qIJKJCYFRLVSALsvg3avjReOjuYk91Q0hFXMJ2KaEM1Y3tdzcFN0fKBiaHexgbFIUk8zJuS4dJObTqSYMXowbg==", "cpu": [ "x64" ], @@ -5594,9 +5036,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.1.2.tgz", - "integrity": "sha512-AXEwOk0lhbWdy4OZmde0iC1sP/AAUMrw5a8Ah7S0QOXBj8X9wK1zyThviQnY1NpUzYGBbMkv3UgPDTArTdAeKA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.3.4.tgz", + "integrity": "sha512-UxC8mRkFTPdZbKFprZkiBqVw8624xU38kI0xyooxKlFpt5lccTBwJ0B7+R8p1RoWyvh2DSyFI9VvfD7lczg1lA==", "cpu": [ "arm64" ], @@ -5626,8 +5068,7 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -5635,9 +5076,8 @@ }, "node_modules/@pkgr/core": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -5646,226 +5086,364 @@ } }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "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.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", "cpu": [ - "ppc64" + "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", "cpu": [ - "riscv64" + "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", "cpu": [ - "s390x" + "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", "cpu": [ - "x64" + "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", "cpu": [ - "x64" + "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", "cpu": [ - "ia32" + "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ] }, - "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==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" ] }, "node_modules/@scarf/scarf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.3.0.tgz", - "integrity": "sha512-lHKK8M5CTcpFj2hZDB3wIjb0KAbEOgDmiJGDv1WBRfQgRm/a8/XMEkG/N1iM01xgbUDsPQwi42D+dFo1XPAKew==", - "hasInstallScript": true + "hasInstallScript": true, + "license": "Apache-2.0" }, "node_modules/@schematics/angular": { - "version": "17.3.8", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.8.tgz", - "integrity": "sha512-2g4OmSyE9YGq50Uj7fNI26P/TSAFJ7ZuirwTF2O7Xc4XRQ29/tYIIqhezpNlTb6rlYblcQuMcUZBrMfWJHcqJw==", + "version": "17.3.7", + "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.8", - "@angular-devkit/schematics": "17.3.8", + "@angular-devkit/core": "17.3.7", + "@angular-devkit/schematics": "17.3.7", "jsonc-parser": "3.2.1" }, "engines": { @@ -5875,11 +5453,10 @@ } }, "node_modules/@sigstore/bundle": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", - "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "version": "2.3.1", + "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -5887,28 +5464,25 @@ }, "node_modules/@sigstore/core": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", - "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/protobuf-specs": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", - "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", + "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/sign": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", - "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "version": "2.3.1", + "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.3.2", + "@sigstore/bundle": "^2.3.0", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/protobuf-specs": "^0.3.1", "make-fetch-happen": "^13.0.1", "proc-log": "^4.2.0", "promise-retry": "^2.0.1" @@ -5919,18 +5493,16 @@ }, "node_modules/@sigstore/sign/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@sigstore/tuf": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", - "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "version": "2.3.3", + "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/protobuf-specs": "^0.3.0", "tuf-js": "^2.2.1" }, "engines": { @@ -5938,66 +5510,86 @@ } }, "node_modules/@sigstore/verify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", - "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "version": "1.2.0", + "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.3.2", + "@sigstore/bundle": "^2.3.1", "@sigstore/core": "^1.1.0", - "@sigstore/protobuf-specs": "^0.3.2" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@simple-libs/child-process-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-1.0.2.tgz", + "integrity": "sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node10": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "license": "MIT", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@tufjs/models": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", - "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "license": "MIT", "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.4" @@ -6006,41 +5598,24 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@types/angular": { "version": "1.5.11", - "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.5.11.tgz", - "integrity": "sha512-Nth2ys1RPMZfOQIs8yveTGBa/5dJ4PhSznm87dinYtQBKFzg7CBO4YqNWGuPibSkQ/uBbcYlnbBFHH7EdeMI3Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/jquery": "1.10.*" } }, "node_modules/@types/babel-types": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.15.tgz", - "integrity": "sha512-JUgfZHUOMbtjopxiOQaaF+Uovk5wpDqpXR+XLWiOivCWSy1FccO30lvNNpCt8geFwq8VmGT2y9OMkOpA0g5O5g==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/@types/babylon": { "version": "6.16.9", - "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.9.tgz", - "integrity": "sha512-sEKyxMVEowhcr8WLfN0jJYe4gS4Z9KC2DGz0vqfC7+MXFbmvOF7jSjALC77thvAO2TLgFUPa9vDeOak+AcUrZA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/babel-types": "*" @@ -6048,9 +5623,8 @@ }, "node_modules/@types/body-parser": { "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6058,33 +5632,29 @@ }, "node_modules/@types/bonjour": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/canvas-confetti": { "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.6.4.tgz", - "integrity": "sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/connect": { "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6092,30 +5662,26 @@ }, "node_modules/@types/cookie": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/cors": { "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/d3": { "version": "3.5.53", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.53.tgz", - "integrity": "sha512-8yKQA9cAS6+wGsJpBysmnhlaaxlN42Qizqkw+h2nILSlS+MAG2z4JdO6p+PJrJ+ACvimkmLJL281h157e52psQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/eslint": { "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -6123,25 +5689,24 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6150,10 +5715,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz", - "integrity": "sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==", + "version": "4.19.0", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6163,147 +5727,117 @@ }, "node_modules/@types/file-saver": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", - "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-errors": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/jasmine": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.9.1.tgz", - "integrity": "sha512-PVpjh8S8lqKFKurWSKdFATlfBHGPzgy0PoDdzQ+rr78jTQ0aacyh9YndzZcAUPxhk4kRujItFFGQdUJ7flHumw==", - "dev": true + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-6.0.0.tgz", + "integrity": "sha512-18lgGsLmEh3VJk9eZ5wAjTISxdqzl6YOwu8UdMpolajN57QOCNbl+AbHUd+Yu9ItrsFdB+c8LSZSGNg8nHaguw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/jasminewd2": { "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.13.tgz", - "integrity": "sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==", "dev": true, + "license": "MIT", "dependencies": { "@types/jasmine": "*" } }, "node_modules/@types/jquery": { "version": "1.10.45", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-1.10.45.tgz", - "integrity": "sha512-JvoVtPbu1wrcOldn5gvuyJqr7DLX6I657N68Fqj5S7AUutdYZqabQjfP7dY6Gee7/Afo1uajwcORVlQfnsjkLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==", - "dev": true + "version": "4.17.1", + "dev": true, + "license": "MIT" }, "node_modules/@types/mime": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/minimatch": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.1.tgz", - "integrity": "sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==", + "version": "20.12.11", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/node-forge": { "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, "node_modules/@types/q": { "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/qs": { "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", - "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -6311,18 +5845,16 @@ }, "node_modules/@types/serve-index": { "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6331,36 +5863,35 @@ }, "node_modules/@types/sockjs": { "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ws": { "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", - "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "version": "7.8.0", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/type-utils": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", + "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -6380,65 +5911,15 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", - "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", - "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", - "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "version": "7.8.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "engines": { @@ -6458,13 +5939,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", - "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", + "version": "7.8.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6475,13 +5955,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", - "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", + "version": "7.8.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6501,11 +5980,10 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "node_modules/@typescript-eslint/types": { + "version": "7.8.0", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -6514,14 +5992,13 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.8.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6542,14 +6019,18 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "node_modules/@typescript-eslint/utils": { + "version": "7.8.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.11.0", - "eslint-visitor-keys": "^3.4.3" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "semver": "^7.6.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6557,28 +6038,19 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.8.0", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" + "@typescript-eslint/types": "7.8.0", + "eslint-visitor-keys": "^3.4.3" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", - "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", - "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -6587,199 +6059,25 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", - "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", - "dev": true, + "node_modules/@uirouter/angular": { + "version": "13.0.0", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "tslib": "^2.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.0.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "@uirouter/core": "^6.0.8", + "@uirouter/rx": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", - "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", - "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.11.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", - "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.12.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@uirouter/angular": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@uirouter/angular/-/angular-13.0.0.tgz", - "integrity": "sha512-T2aizSXzW+7eiXUmc0LiLH+I8ZBJvDr7OQmm/5WCcxVL2NfuIse7B1kpvfdh9PmBAqw8AY7S0NhrJgABfFJUnw==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "@angular/common": "^17.0.0", - "@angular/core": "^17.0.0", - "@uirouter/core": "^6.0.8", - "@uirouter/rx": "^1.0.0" - } - }, - "node_modules/@uirouter/angular-hybrid": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/angular-hybrid/-/angular-hybrid-17.1.0.tgz", - "integrity": "sha512-zUQ/b2BaEuODPOtDtxp2SpEifm/VHoLauPTXtZAfcHpDoty6DFbLyGCrA4ZI9lqyoACVxpOuUKjhTHLNE9SXTw==", + "node_modules/@uirouter/angular-hybrid": { + "version": "17.1.0", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -6794,8 +6092,7 @@ }, "node_modules/@uirouter/angularjs": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.1.0.tgz", - "integrity": "sha512-AhgxXhMfN6FU2HxDQqwDPbzmd6kTgvYCgV/kgoCAXfxAH6cFQrifViToC90Wdg6djBynHwA3L/KYP+iOYHkw6A==", + "license": "MIT", "engines": { "node": ">=4.0.0" }, @@ -6806,16 +6103,14 @@ }, "node_modules/@uirouter/core": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.1.0.tgz", - "integrity": "sha512-WFYh5NPAqRX4L2qlI4k62tgR6pxoqOBSW1CM1uBWCau4mAmgasYd5etJ9RoSJrSnCpCQ2km2Jltf0n5ql684MQ==", + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/@uirouter/rx": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@uirouter/rx/-/rx-1.0.0.tgz", - "integrity": "sha512-dqPmLFC+qqF6RIdJVKktXSON6WILy2oyLhADDk74F3GAUZ/VvOu3QSPLDtZEP3LMSo6vkGQvwcUdjgNVWL3YJA==", + "license": "MIT", "peerDependencies": { "@uirouter/core": ">=6.0.1", "rxjs": "^6.5.3 || ^7.4.0" @@ -6823,15 +6118,13 @@ }, "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 + "dev": true, + "license": "ISC" }, "node_modules/@vitejs/plugin-basic-ssl": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", - "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -6841,9 +6134,8 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -6851,27 +6143,23 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -6880,15 +6168,13 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -6898,33 +6184,29 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -6938,9 +6220,8 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -6951,9 +6232,8 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -6963,9 +6243,8 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -6977,36 +6256,47 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, + "node_modules/@worktile/gantt": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@worktile/gantt/-/gantt-18.0.5.tgz", + "integrity": "sha512-LCcWaFBmeg5u9cVDEmREHdR+qJJHE3Ld4VxdoJpTXfhDkx2f19tp0wMR9MkwOLRwwTCx/5gGJ1kTbz4P0Zfc1Q==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=17.0.0", + "@angular/common": ">=17.0.0", + "@angular/core": ">=17.0.0", + "date-fns": ">=2.0.0", + "rxjs": "^6.5.0 || ^7.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==" + "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==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "js-yaml": "^3.10.0", "tslib": "^2.4.0" @@ -7016,10 +6306,9 @@ } }, "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==", + "version": "0.0.6", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -7029,20 +6318,18 @@ }, "node_modules/@zkochan/js-yaml/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "devOptional": true, + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -7053,9 +6340,8 @@ }, "node_modules/acorn": { "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -7065,9 +6351,8 @@ }, "node_modules/acorn-globals": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha512-uWttZCk96+7itPxK8xCzY86PnxKTMrReKDqrHzv42VQY0K30PUO8WY13WMOuI+cOdX4EIdzdvQ8k6jkuGRFMYw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "acorn": "^4.0.4" @@ -7075,9 +6360,8 @@ }, "node_modules/acorn-globals/node_modules/acorn": { "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", "dev": true, + "license": "MIT", "optional": true, "bin": { "acorn": "bin/acorn" @@ -7088,659 +6372,196 @@ }, "node_modules/acorn-import-assertions": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^8" } }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" }, "engines": { - "node": ">=8.9" - } - }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/adm-zip": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.13.tgz", - "integrity": "sha512-4U51tTl9J8UVEcuKGr6zRzY95tWoAa9l+ureGBNmsfleszjZblm5NyEEL/ZQxkhi86co5mZhSvL2T7gkZ6feYQ==", - "dev": true, - "engines": { - "node": ">=12.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "dev": true, - "optional": true, - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/align-text/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "optional": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/alter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz", - "integrity": "sha512-Wuss6JIZ6h4j2+NgU2t+9mSwS7gBSZJbU4Dg8xETguAD2veJUSuCrvTIiC78QgZE7/zX7h6OnXw2PiiCBirEGw==", - "dev": true, - "dependencies": { - "stable": "~0.1.3" - } - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/angular": { - "version": "1.5.11", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.5.11.tgz", - "integrity": "sha512-09DBOVVWo6rOQfdCBKGfEL0ZZIhf6P3fbeP3BU+ty5FU50DPiavVeDn8hQ4wXE8o4vKEEpzY1aRcRHJMCixWYA==", - "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." - }, - "node_modules/angular-cookies": { - "version": "1.5.11", - "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.5.11.tgz", - "integrity": "sha512-WyUrigFcnxLZnzaupIAqOLrGXMCOcGz0L5O7OoaWKYGvEx2yNvGSNAGJCmOggGmaPEfIt6YMGTcbc4uwS6Srdw==", - "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." - }, - "node_modules/angular-file-upload": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/angular-file-upload/-/angular-file-upload-1.1.6.tgz", - "integrity": "sha512-lIH9G02tShyxhH5bQyMkUA5vncVT7KoMBbIklywzU20p7Q/P3xQUb3oxx/smXLXfjYQOiiQyoEILYLFJC4WYMw==", - "dependencies": { - "coffee-script": "~1.6.2", - "grunt": "~0.4.1", - "grunt-contrib-clean": "~0.4.0", - "grunt-contrib-concat": "~0.3.0", - "grunt-contrib-copy": "~0.4.1", - "grunt-contrib-uglify": "~0.2.1" - } - }, - "node_modules/angular-file-upload/node_modules/argparse": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", - "dependencies": { - "underscore": "~1.7.0", - "underscore.string": "~2.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/argparse/node_modules/underscore.string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/angular-file-upload/node_modules/colors": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/angular-file-upload/node_modules/dateformat": { - "version": "1.0.2-1.2.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", - "integrity": "sha512-AXvW8g7tO4ilk5HgOWeDmPi/ZPaCnMJ+9Cg1I3p19w6mcvAAXBuuGEXAxybC+Djj1PSZUiHUcyoYu7WneCX8gQ==", - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/findup-sync": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", - "integrity": "sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw==", - "dependencies": { - "glob": "~3.2.9", - "lodash": "~2.4.1" - }, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/angular-file-upload/node_modules/findup-sync/node_modules/glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "inherits": "2", - "minimatch": "0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/findup-sync/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/angular-file-upload/node_modules/findup-sync/node_modules/minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha512-hIGEBfnHcZpWkXPsAVeVmpYDvfy/matVl03yOY91FPmnpCC12Lm5izNxCjO3lHAeO6uaTwMxu7g450Siknlhig==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/angular-file-upload/node_modules/glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - }, - "engines": { - "node": "*" - } - }, - "node_modules/angular-file-upload/node_modules/glob/node_modules/inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==" - }, - "node_modules/angular-file-upload/node_modules/graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ==", - "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha512-1iq3ylLjzXqz/KSq1OAE2qhnpcbkF2WyhsQcavZt+YmgvHu0EbPMEhGhy2gr0FP67isHpRdfwjB5WVeXXcJemQ==", - "dependencies": { - "async": "~0.1.22", - "coffee-script": "~1.3.3", - "colors": "~0.6.2", - "dateformat": "1.0.2-1.2.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.1.2", - "getobject": "~0.1.0", - "glob": "~3.1.21", - "grunt-legacy-log": "~0.1.0", - "grunt-legacy-util": "~0.2.0", - "hooker": "~0.2.3", - "iconv-lite": "~0.2.11", - "js-yaml": "~2.0.5", - "lodash": "~0.9.2", - "minimatch": "~0.2.12", - "nopt": "~1.0.10", - "rimraf": "~2.2.8", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-contrib-clean": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.4.1.tgz", - "integrity": "sha512-PajoaZgwbJ1QAbY5CemvuCIXUJU8teoA3ABTd3eZA+j0UYTUBW+hlV5m3ZlZLgRxKm3ZrchAEVR85r5uBeKF9w==", - "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-contrib-concat": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.3.0.tgz", - "integrity": "sha512-w5N63mMgEYAEhd9PgY8uQ0pY02SucTSwq8XRTtHyEt7MSMQLlp7lF0g5oaXSav9xCWY9GPM0RqlJTT2gS+8n3Q==", - "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-contrib-copy": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.4.1.tgz", - "integrity": "sha512-My7R1hjkV6k/6WFkwHguB//y1kcV65X9U37XnAJWwmfGAsoAVlXFRNYN0W62W2D0TbLXLX24fiH4q1/5Bugf+A==", - "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-contrib-uglify": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.2.7.tgz", - "integrity": "sha512-KXKM2UNLsCiUI6/DYfAIPm3i26UJJN6Cf6KD8fFa2TKllj7yLPC853IxtWBJ/3jX66QtXHGtdCORuuA6sAFvvA==", - "dependencies": { - "grunt-lib-contrib": "~0.6.1", - "uglify-js": "~2.4.0" - }, - "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-log": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha512-qYs/uM0ImdzwIXLhS4O5WLV5soAM+PEqqHI/hzSxlo450ERSccEhnXqoeDA9ZozOdaWuYnzTOTwRcVRogleMxg==", - "dependencies": { - "colors": "~0.6.2", - "grunt-legacy-log-utils": "~0.1.1", - "hooker": "~0.2.3", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-log-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha512-D0vbUX00TFYCKNZtcZzemMpwT8TR/FdRs1pmfiBw6qnUw80PfsjV+lhIozY/3eJ3PSG2zj89wd2mH/7f4tNAlw==", - "dependencies": { - "colors": "~0.6.2", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-log-utils/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-log/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-util": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha512-cXPbfF8aM+pvveQeN1K872D5fRm30xfJWZiS63Y8W8oyIPLClCsmI8bW96Txqzac9cyL4lRqEBhbhJ3n5EzUUQ==", - "dependencies": { - "async": "~0.1.22", - "exit": "~0.1.1", - "getobject": "~0.1.0", - "hooker": "~0.2.3", - "lodash": "~0.9.2", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/angular-file-upload/node_modules/grunt-legacy-util/node_modules/underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", - "engines": { - "node": "*" + "node": ">=8.9" } }, - "node_modules/angular-file-upload/node_modules/grunt/node_modules/coffee-script": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", - "integrity": "sha512-QjQ1T4BqyHv19k6XSfdhy/QLlIOhywz0ekBUCa9h71zYMJlfDTGan/Z1JXzYkZ6v8R+GhvL/p4FZPbPW8WNXlg==", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=0.4.0" + "node": ">=8.9.0" } }, - "node_modules/angular-file-upload/node_modules/grunt/node_modules/underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", + "node_modules/adm-zip": { + "version": "0.5.12", + "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=6.0" } }, - "node_modules/angular-file-upload/node_modules/iconv-lite": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==", + "node_modules/agent-base": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, "engines": { - "node": ">=0.4.0" + "node": ">= 14" } }, - "node_modules/angular-file-upload/node_modules/js-yaml": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha512-VEKcIksckDBUhg2JS874xVouiPkywVUh4yyUmLCDe1Zg3bCd6M+F1eGPenPeHLc2XC8pp9G8bsuofK0NeEqRkA==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "license": "MIT", "dependencies": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">= 0.6.0" + "node": ">=8" } }, - "node_modules/angular-file-upload/node_modules/lodash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha512-LVbt/rjK62gSbhehDVKL0vlaime4Y1IBixL+bKeNfoY4L2zab/jGrxU6Ka05tMA/zBxkTk5t3ivtphdyYupczw==", - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/angular-file-upload/node_modules/lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==" - }, - "node_modules/angular-file-upload/node_modules/minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, - "engines": { - "node": "*" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/angular-file-upload/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "node_modules/ajv-formats": { + "version": "2.1.1", + "license": "MIT", "dependencies": { - "abbrev": "1" + "ajv": "^8.0.0" }, - "bin": { - "nopt": "bin/nopt.js" + "peerDependencies": { + "ajv": "^8.0.0" }, - "engines": { - "node": "*" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/angular-file-upload/node_modules/rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "bin": { - "rimraf": "bin.js" + "node_modules/ajv-keywords": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/angular-file-upload/node_modules/source-map": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", - "integrity": "sha512-yfCwDj0vR9RTwt3pEzglgb3ZgmcXHt6DjG3bjJvzPwTL+5zDQ2MhmSzAcTy0GTiQuCiriSWXvWM1/NhKdXuoQA==", + "node_modules/align-text": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "amdefine": ">=0.0.4" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" } }, - "node_modules/angular-file-upload/node_modules/uglify-js": { - "version": "2.4.24", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", - "integrity": "sha512-tktIjwackfZLd893KGJmXc1hrRHH1vH9Po3xFh1XBjjeGAnN02xJ3SuoA+n1L29/ZaCA18KzCFlckS+vfPugiA==", + "node_modules/align-text/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "async": "~0.2.6", - "source-map": "0.1.34", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.5.4" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/angular-file-upload/node_modules/uglify-js/node_modules/async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" - }, - "node_modules/angular-file-upload/node_modules/underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==" - }, - "node_modules/angular-file-upload/node_modules/which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", - "bin": { - "which": "bin/which" + "node_modules/alter": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "stable": "~0.1.3" } }, - "node_modules/angular-file-upload/node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "engines": { - "node": ">=0.4.0" + "node_modules/angular": { + "version": "1.5.11", + "license": "MIT" + }, + "node_modules/angular-calendar": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.31.1.tgz", + "integrity": "sha512-pjSIpoAaUzS/gx+14eOr4hPZhlQ8HxpiZypCSGqJNptq5PD+vOdVQ3h/Aaqnk86GraVcAQPXqfu64MtdKwTVNw==", + "license": "MIT", + "dependencies": { + "@scarf/scarf": "^1.1.1", + "angular-draggable-droppable": "^8.0.0", + "angular-resizable-element": "^7.0.0", + "calendar-utils": "^0.10.4", + "positioning": "^2.0.1", + "tslib": "^2.4.1" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" } }, - "node_modules/angular-file-upload/node_modules/yargs": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", - "integrity": "sha512-5j382E4xQSs71p/xZQsU1PtRA2HXPAjX0E0DkoGLxwNASMOKX6A9doV1NrZmj85u2Pjquz402qonBzz/yLPbPA==", + "node_modules/angular-draggable-droppable": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-8.0.0.tgz", + "integrity": "sha512-+gpSNBbygjV1pxTxsM3UPJKcXHXJabYoTtKcgQe74rGnb1umKc07XCBD1qDzvlG/kocthvhQ12qfYOYzHnE3ZA==", + "license": "MIT", "dependencies": { - "camelcase": "^1.0.2", - "decamelize": "^1.0.0", - "window-size": "0.1.0", - "wordwrap": "0.0.2" + "@mattlewis92/dom-autoscroller": "^2.4.2", + "tslib": "^2.4.1" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" } }, "node_modules/angular-filter": { "version": "0.5.17", - "resolved": "https://registry.npmjs.org/angular-filter/-/angular-filter-0.5.17.tgz", - "integrity": "sha512-jWZuok808roBwEiNZ2IiBzKD7gf4vWTDzbp9RhhZO9usQxTiywsZ3O94X75MOHBtOzM/rxbI78sHw3Y2sz40QQ==", + "license": "MIT", "dependencies": { "angular": "*" }, @@ -7748,55 +6569,54 @@ "node": ">=0.10.0" } }, - "node_modules/angular-local-storage": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/angular-local-storage/-/angular-local-storage-0.7.1.tgz", - "integrity": "sha512-AJgX9+f8eWpsnSuPrNZ/G3TdH/iBtlEdOUgLohbddTrwJ+E0+tfHtXKNgYpYh7iN6aM6subYmn0KfvZBBaLdfw==" - }, "node_modules/angular-markdown-filter": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/angular-markdown-filter/-/angular-markdown-filter-1.3.2.tgz", - "integrity": "sha512-2dr3IB/d9dyLTH36nE61Qkxm078sOpHvpd4Q863eXEgrwsre8YySxWsgaq1qooY3P7C7wQ1LhFGvh5rAA25wnA==", + "license": "MIT", "dependencies": { "showdown": "^1.2.3" } }, "node_modules/angular-md5": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/angular-md5/-/angular-md5-0.1.10.tgz", - "integrity": "sha512-hGDEDxGdy8ZMC9eV7DXDc8FnwY0vaYLLZW8OX/7oBwGdA9K5UcK1hHZiYFznBwYbMoo+x50iMmY5Xfn1JunMDA==" + "version": "0.1.10" }, "node_modules/angular-mocks": { - "version": "1.5.11", - "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.5.11.tgz", - "integrity": "sha512-eDVhiwiHlMEK6W47sIkiZh4We35Lqskg+G5rSTpUBPndwd2XM/uwuW+eklzOZhx+ODaFLuMsxeLY1h9rA3utIA==" + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.8.3.tgz", + "integrity": "sha512-vqsT6zwu80cZ8RY7qRQBZuy6Fq5X7/N5hkV9LzNT0c8b546rw4ErGK6muW1u2JnDKYa7+jJuaGM702bWir4HGw==", + "license": "MIT" }, "node_modules/angular-nvd3": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/angular-nvd3/-/angular-nvd3-1.0.9.tgz", - "integrity": "sha512-FcGYVXeNejlDj+Yr6g3ydRT+kuLAzKY/KMuc4eiLJbSvRcSqfLJtrFZi6wFXGhW3OlbLHvCjAeFzDvTac3gNTQ==", + "license": "MIT", "dependencies": { "angular": "^1.x", "d3": "^3.3", "nvd3": "^1.7.1" } }, + "node_modules/angular-resizable-element": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-7.0.2.tgz", + "integrity": "sha512-/BGuNiA38n9klexHO1xgnsA3VYigj9v+jUGjKtBRgfB26bCxZKsNWParSu2k3EqbATrfAJC4Nl8f7cORpJFf4w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" + } + }, "node_modules/angular-resource": { "version": "1.5.11", - "resolved": "https://registry.npmjs.org/angular-resource/-/angular-resource-1.5.11.tgz", - "integrity": "sha512-OlJJ+pxCu2PoyWrlkEeLjP7jmo7WtYHuWYdT8s1IpLVHYk4rfK7+uD5Zua99Yi1ZS/x9nU+mBiAupp46mBPayA==", - "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." + "license": "MIT" }, "node_modules/angular-sanitize": { "version": "1.5.11", - "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.5.11.tgz", - "integrity": "sha512-9yVOr8YOefo0/4q+ImqNdGcbfGzelQIoHW0OoaoU/U5wpRZNn5IqlkdLW9udieSiprYzuXeqiS1V7ZiHurYisw==", - "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." + "license": "MIT" }, "node_modules/angular-ui-bootstrap": { "version": "0.13.4", - "resolved": "https://registry.npmjs.org/angular-ui-bootstrap/-/angular-ui-bootstrap-0.13.4.tgz", - "integrity": "sha512-/g6Z9kKbAuC7Ardhdp4PsvJJVXNdxinXy+qdAWo2wog/hPC2evSfVBs1fksc0XhZo/4XCFznbLKfOmM7NZMkbQ==", + "license": "MIT", "peerDependencies": { "angular": "^1.3.x || >= 1.4.0-beta.0 || >= 1.5.0-beta.0", "bootstrap": "^3.x" @@ -7804,13 +6624,11 @@ }, "node_modules/angular-ui-codemirror": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/angular-ui-codemirror/-/angular-ui-codemirror-0.3.0.tgz", - "integrity": "sha512-C1zlnNoX1PS4Oa+R3RomhwMuwiyhMeCZB/WnDg+RJ1G/1G7tUWK7JUCXW1NjhZ8pE5wYR5LV0hoGTHWGR4H9kQ==" + "license": "MIT" }, "node_modules/angular-xeditable": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/angular-xeditable/-/angular-xeditable-0.9.0.tgz", - "integrity": "sha512-ss1M4VGUmXeIxnPEKRhOE7iTkfPnjYQ0yYCjv8SdrM2WHet4ULw4IDTkr7vuq1WMn0Nd29QijTwTDZNZQFJfyw==", + "license": "MIT", "dependencies": { "angular": "~1.x" }, @@ -7819,30 +6637,25 @@ } }, "node_modules/angulartics": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/angulartics/-/angulartics-1.0.3.tgz", - "integrity": "sha512-CwLgHvuj2IuJWXJHWn14gwiRCaNrlk1eUCZdGIFnPcHJ+QXlaIzmDyLuoC7oXQeSxC5NTs0B37rH9Yp6lOM9UQ==" + "version": "1.0.3" }, "node_modules/angulartics-google-analytics": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/angulartics-google-analytics/-/angulartics-google-analytics-0.1.4.tgz", - "integrity": "sha512-v8whl/PQPajKhq/HlpM0776x31KLFvhWdGEm4z/4hw2uE4VlGshocsjgzqz3pB6k2FZlWncYqMu1TzxXTHqJKg==", + "license": "MIT", "peerDependencies": { "angulartics": "~1.0.0" } }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -7855,28 +6668,25 @@ }, "node_modules/ansi-html-community": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "dev": true, "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -7886,15 +6696,13 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "devOptional": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -7905,9 +6713,8 @@ }, "node_modules/anymatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7916,9 +6723,10 @@ } }, "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", "optional": true }, "node_modules/are-we-there-yet": { @@ -7926,6 +6734,7 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "delegates": "^1.0.0", @@ -7937,60 +6746,53 @@ }, "node_modules/arg": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "dev": true, + "license": "MIT" }, "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/aria-query": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" } }, "node_modules/arr-diff": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/arr-flatten": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/arr-union": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -8004,39 +6806,34 @@ }, "node_modules/array-differ": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array-each": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-ify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-includes": { "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -8054,45 +6851,40 @@ }, "node_modules/array-slice": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.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" } }, "node_modules/array-uniq": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/array-unique": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/array.prototype.flat": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -8108,9 +6900,8 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -8130,76 +6921,67 @@ }, "node_modules/arrify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/asn1": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } }, "node_modules/assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/assign-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/async-each": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } - ] + ], + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/atob": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true, + "license": "(MIT OR Apache-2.0)", "bin": { "atob": "bin/atob.js" }, @@ -8209,9 +6991,8 @@ }, "node_modules/autoprefixer": { "version": "6.7.7", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", - "integrity": "sha512-WKExI/eSGgGAkWAO+wMVdFObZV7hQen54UpD1kCCTN3tvlL3W1jL4+lPP/M7MwoP7Q4RHzKtO3JQ4HxYEcd+xQ==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^1.7.6", "caniuse-db": "^1.0.30000634", @@ -8223,28 +7004,24 @@ }, "node_modules/autoprefixer/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/autoprefixer/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/autoprefixer/node_modules/browserslist": { "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha512-qHJblDE2bXVRYzuDetv/wAeHOJyO97+9wxC1cdCtyzgNuSozOyRCiiLaCR1f71AN66lQdVVBipWm63V+a7bPOw==", - "deprecated": "Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.", "dev": true, + "license": "MIT", "dependencies": { "caniuse-db": "^1.0.30000639", "electron-to-chromium": "^1.2.7" @@ -8255,9 +7032,8 @@ }, "node_modules/autoprefixer/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -8271,27 +7047,24 @@ }, "node_modules/autoprefixer/node_modules/chalk/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/autoprefixer/node_modules/has-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/autoprefixer/node_modules/postcss": { "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.1.3", "js-base64": "^2.1.9", @@ -8304,18 +7077,16 @@ }, "node_modules/autoprefixer/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/autoprefixer/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -8325,9 +7096,8 @@ }, "node_modules/autoprefixer/node_modules/supports-color": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^1.0.0" }, @@ -8337,9 +7107,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -8352,44 +7121,41 @@ }, "node_modules/aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", - "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==", - "dev": true + "version": "1.12.0", + "dev": true, + "license": "MIT" }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "dev": true, + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "node_modules/axobject-query": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" } }, "node_modules/babel-loader": { "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, + "license": "MIT", "dependencies": { "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" @@ -8404,9 +7170,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -8420,9 +7185,8 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -8434,18 +7198,16 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", - "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0", "core-js-compat": "^3.34.0" @@ -8456,9 +7218,8 @@ }, "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -8472,9 +7233,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0" }, @@ -8484,9 +7244,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -8500,9 +7259,8 @@ }, "node_modules/babel-runtime": { "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "core-js": "^2.4.0", @@ -8511,25 +7269,21 @@ }, "node_modules/babel-runtime/node_modules/core-js": { "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true }, "node_modules/babel-runtime/node_modules/regenerator-runtime": { "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/babel-types": { "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "babel-runtime": "^6.26.0", @@ -8540,9 +7294,8 @@ }, "node_modules/babel-types/node_modules/to-fast-properties": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -8550,9 +7303,8 @@ }, "node_modules/babylon": { "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "babylon": "bin/babylon.js" @@ -8560,14 +7312,12 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "license": "MIT" }, "node_modules/base": { "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, + "license": "MIT", "dependencies": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -8583,9 +7333,8 @@ }, "node_modules/base/node_modules/define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.0" }, @@ -8595,9 +7344,8 @@ }, "node_modules/base/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -8606,10 +7354,17 @@ "node": ">= 0.4" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -8623,22 +7378,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, + "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } }, "node_modules/basic-auth": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -8648,33 +7402,29 @@ }, "node_modules/batch": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } }, "node_modules/big.js": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -8694,8 +7444,7 @@ }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -8704,9 +7453,8 @@ }, "node_modules/blocking-proxy": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -8719,8 +7467,6 @@ }, "node_modules/body": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "dependencies": { "continuable-cache": "^0.3.1", @@ -8731,9 +7477,8 @@ }, "node_modules/body-parser": { "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -8755,18 +7500,16 @@ }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -8776,15 +7519,13 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/body-parser/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, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -8794,15 +7535,12 @@ }, "node_modules/body/node_modules/bytes": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, "node_modules/body/node_modules/raw-body": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "1", "string_decoder": "0.10" @@ -8813,15 +7551,13 @@ }, "node_modules/body/node_modules/string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -8829,38 +7565,33 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/bootstrap": { "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/bootstrap-sass": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.4.3.tgz", - "integrity": "sha512-vPgFnGMp1jWZZupOND65WS6mkR8rxhJxndT/AcMbqcq1hHMdkcH4sMPhznLzzoHOHkSCrd6J9F8pWBriPCKP2Q==" + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "version": "3.0.2", "devOptional": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "fill-range": "^7.0.1" }, "engines": { "node": ">=8" @@ -8868,8 +7599,6 @@ }, "node_modules/browserslist": { "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -8885,6 +7614,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -8900,18 +7630,16 @@ }, "node_modules/browserstack": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", "dev": true, + "license": "MIT", "dependencies": { "https-proxy-agent": "^2.2.1" } }, "node_modules/browserstack/node_modules/agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "license": "MIT", "dependencies": { "es6-promisify": "^5.0.0" }, @@ -8921,18 +7649,16 @@ }, "node_modules/browserstack/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/browserstack/node_modules/https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -8943,8 +7669,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -8959,6 +7683,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -8966,23 +7691,20 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { "version": "18.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", - "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -9002,15 +7724,14 @@ } }, "node_modules/cacache/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.3.15", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -9024,31 +7745,15 @@ }, "node_modules/cacache/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/cache-base": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, + "license": "MIT", "dependencies": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -9064,10 +7769,15 @@ "node": ">=0.10.0" } }, + "node_modules/calendar-utils": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/calendar-utils/-/calendar-utils-0.10.4.tgz", + "integrity": "sha512-gBK4xCJ42yjaUKwuUha6cZOfxAmGzvSgbdAaX3xLRioeKbYoOK1x1qeD6dch72rsMZlTgATPbBBx42bnkStqgQ==", + "license": "MIT" + }, "node_modules/call-bind": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -9082,20 +7792,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camel-case": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.1" @@ -9103,48 +7824,26 @@ }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase-css": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/caniuse-db": { - "version": "1.0.30001627", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001627.tgz", - "integrity": "sha512-O964NchPabQ18rRShPUZ4eZqVGIBwdWzVUFF2OV7tA95RLVAoCjsGECEM7oqlbKWKQw9XJXskAJ1wYTmQhuMHA==", - "dev": true + "version": "1.0.30001617", + "dev": true, + "license": "CC-BY-4.0" }, "node_modules/caniuse-lite": { - "version": "1.0.30001627", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz", - "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==", + "version": "1.0.30001617", "dev": true, "funding": [ { @@ -9159,19 +7858,20 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/canonical-path": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-0.0.2.tgz", - "integrity": "sha512-y8EIEvL+IW81S4hRQWCRFtly+g1cc1G+wxHpjhYR9jI2+JJjWiaKnkH8mmvNHOMOAd9fzgARDO3AEzjuR51qaA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/canvas": { "version": "2.11.2", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", @@ -9184,8 +7884,7 @@ }, "node_modules/canvas-confetti": { "version": "1.9.3", - "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz", - "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==", + "license": "ISC", "funding": { "type": "donate", "url": "https://www.paypal.me/kirilvatev" @@ -9193,15 +7892,13 @@ }, "node_modules/caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/center-align": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "align-text": "^0.1.3", @@ -9213,9 +7910,8 @@ }, "node_modules/chalk": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -9227,9 +7923,8 @@ }, "node_modules/character-parser": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", - "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "is-regex": "^1.0.3" @@ -9237,14 +7932,12 @@ }, "node_modules/chardet": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + "license": "MIT" }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "devOptional": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -9266,26 +7959,23 @@ }, "node_modules/chownr": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "version": "1.0.3", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/class-utils": { "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, + "license": "MIT", "dependencies": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -9298,9 +7988,8 @@ }, "node_modules/clean-css": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "~0.6.0" }, @@ -9310,26 +7999,23 @@ }, "node_modules/clean-css/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/clean-stack": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/cli": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", "dev": true, + "license": "MIT", "dependencies": { "exit": "0.1.2", "glob": "^7.1.1" @@ -9340,8 +8026,7 @@ }, "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==", + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -9351,8 +8036,7 @@ }, "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==", + "license": "MIT", "engines": { "node": ">=6" }, @@ -9362,16 +8046,14 @@ }, "node_modules/cli-width": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", "engines": { "node": ">= 12" } }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -9383,8 +8065,7 @@ }, "node_modules/cliui/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9397,8 +8078,7 @@ }, "node_modules/cliui/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9408,13 +8088,11 @@ }, "node_modules/cliui/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9429,17 +8107,15 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/clone-deep": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -9451,27 +8127,12 @@ }, "node_modules/codemirror": { "version": "5.65.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.0.tgz", - "integrity": "sha512-gWEnHKEcz1Hyz7fsQWpK7P0sPI2/kSkRX2tc7DFA6TmZuDN75x/1ejnH/Pn8adYKrLEA1V2ww6L00GudHZbSKw==" - }, - "node_modules/coffee-script": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.3.tgz", - "integrity": "sha512-lpusDYw9xym9ZOqFIeQuzzvTvunm2nlRL++BYhUcLn+77vuidExZG+qDPSKUfDXvuaHeFK6QavntXF+HiOq+/Q==", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" - }, - "engines": { - "node": ">=0.8.0" - } + "license": "MIT" }, "node_modules/coffeelint": { "version": "1.16.2", - "resolved": "https://registry.npmjs.org/coffeelint/-/coffeelint-1.16.2.tgz", - "integrity": "sha512-6mzgOo4zb17WfdrSui/cSUEgQ0AQkW3gXDht+6lHkfkqGUtSYKwGdGcXsDfAyuScVzTlTtKdfwkAlJWfqul7zg==", "dev": true, + "license": "MIT", "dependencies": { "coffee-script": "~1.11.0", "glob": "^7.0.6", @@ -9490,9 +8151,8 @@ }, "node_modules/coffeelint-stylish": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/coffeelint-stylish/-/coffeelint-stylish-0.1.2.tgz", - "integrity": "sha512-VcuzfB0bC9lvdvwckLzh3njKce68VVmOOXp0igyNl50D/uRLbFb4HSjQtTNGFEYiQ9Z0hjhfTqKe4v8UQxnngA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.0.0", "text-table": "^0.2.0" @@ -9504,27 +8164,24 @@ }, "node_modules/coffeelint-stylish/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/coffeelint-stylish/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/coffeelint-stylish/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -9538,9 +8195,8 @@ }, "node_modules/coffeelint-stylish/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -9550,19 +8206,16 @@ }, "node_modules/coffeelint-stylish/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/coffeelint/node_modules/coffee-script": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.11.1.tgz", - "integrity": "sha512-NIWm59Fh1zkXq6TS6PQvSO3AR9DbGq1IBNZHa1E3fUCNmJhIwLf1YKcWgaHqaU7zWGC/OE2V7K3GVAXFzcmu+A==", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", "dev": true, + "license": "MIT", "bin": { "cake": "bin/cake", "coffee": "bin/coffee" @@ -9573,21 +8226,18 @@ }, "node_modules/coffeelint/node_modules/ignore": { "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/coffeelint/node_modules/resolve": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", - "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/coffeelint/node_modules/strip-json-comments": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", "dev": true, + "license": "MIT", "bin": { "strip-json-comments": "cli.js" }, @@ -9597,9 +8247,8 @@ }, "node_modules/collection-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, + "license": "MIT", "dependencies": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -9610,21 +8259,20 @@ }, "node_modules/color-convert": { "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", "optional": true, "bin": { "color-support": "bin.js" @@ -9632,24 +8280,21 @@ }, "node_modules/colorette": { "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -9659,33 +8304,29 @@ }, "node_modules/commander": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha512-PhbTMT+ilDXZKqH8xbvuUY2ZEQNef0Q7DKxgoEKb4ccytsdvVVJmYqR0sGbi96nxU6oGrwEIQnclpK2NBZuQlg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.x" } }, "node_modules/comment-parser": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.0.0" } }, "node_modules/common-path-prefix": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/compare-func": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, + "license": "MIT", "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" @@ -9693,18 +8334,16 @@ }, "node_modules/component-emitter": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/compressible": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9714,9 +8353,8 @@ }, "node_modules/compression": { "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9732,39 +8370,34 @@ }, "node_modules/compression/node_modules/bytes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/compression/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/concurrently": { "version": "3.6.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.1.tgz", - "integrity": "sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^2.4.1", "commander": "2.6.0", @@ -9784,20 +8417,24 @@ "node": ">=4.0.0" } }, + "node_modules/concurrently/node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "node_modules/concurrently/node_modules/has-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/concurrently/node_modules/supports-color": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^1.0.0" }, @@ -9807,9 +8444,8 @@ }, "node_modules/connect": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -9822,41 +8458,35 @@ }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/connect-livereload": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.5.4.tgz", - "integrity": "sha512-3KnRwsWf4VmP01I4hCDQqTc4e2UxOvJIi8i08GiwqX2oymzxNFY7PqjFkwHglYTJ0yzUJkO5yqdPxVaIz3Pbug==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/connect/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/console-browserify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", "dev": true, "dependencies": { "date-now": "^0.1.4" @@ -9866,13 +8496,13 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", "optional": true }, "node_modules/constantinople": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", - "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/babel-types": "^7.0.0", @@ -9883,9 +8513,8 @@ }, "node_modules/content-disposition": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -9895,8 +8524,6 @@ }, "node_modules/content-disposition/node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -9911,94 +8538,86 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/continuable-cache": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "node_modules/conventional-changelog-angular": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", - "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.0.tgz", + "integrity": "sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==", "dev": true, + "license": "ISC", "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" + "compare-func": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", - "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.0.tgz", + "integrity": "sha512-kYFx6gAyjSIMwNtASkI3ZE99U1fuVDJr0yTYgVy+I2QG46zNZfl2her+0+eoviG82c5WQvW1jMt1eOQTeJLodA==", "dev": true, + "license": "ISC", "dependencies": { "compare-func": "^2.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/conventional-commits-parser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz", + "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==", "dev": true, + "license": "MIT", "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" }, "bin": { - "conventional-commits-parser": "cli.js" + "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/convert-source-map": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/copy-anything": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, + "license": "MIT", "dependencies": { "is-what": "^3.14.1" }, @@ -10008,18 +8627,16 @@ }, "node_modules/copy-descriptor": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", @@ -10041,9 +8658,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -10053,9 +8669,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/globby": { "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.3.0", @@ -10072,9 +8687,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/slash": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -10083,20 +8697,18 @@ } }, "node_modules/core-js": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", - "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "version": "3.37.0", "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.37.0", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.23.0" }, @@ -10107,15 +8719,12 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -10125,51 +8734,89 @@ } }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", - "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", + "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", "dev": true, + "license": "MIT", "dependencies": { - "cosmiconfig": "^7", - "ts-node": "^10.8.1" + "jiti": "^2.6.1" }, "engines": { - "node": ">=12", - "npm": ">=6" + "node": ">=v18" }, "peerDependencies": { "@types/node": "*", - "cosmiconfig": ">=7", - "typescript": ">=3" + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cosmiconfig-typescript-loader/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters": { "version": "0.0.22", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", - "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -10182,9 +8829,8 @@ }, "node_modules/critters/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10197,9 +8843,8 @@ }, "node_modules/critters/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10213,9 +8858,8 @@ }, "node_modules/critters/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": { "color-name": "~1.1.4" }, @@ -10225,24 +8869,21 @@ }, "node_modules/critters/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 + "dev": true, + "license": "MIT" }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10251,9 +8892,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10263,11 +8904,19 @@ "node": ">= 8" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -10300,15 +8949,13 @@ }, "node_modules/css-loader/node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/css-select": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -10322,9 +8969,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -10334,9 +8980,8 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -10346,29 +8991,17 @@ }, "node_modules/custom-event": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/d3": { "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==" - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "engines": { - "node": ">=8" - } + "license": "BSD-3-Clause" }, "node_modules/dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -10378,9 +9011,8 @@ }, "node_modules/data-view-buffer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -10395,9 +9027,8 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -10412,9 +9043,8 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -10428,39 +9058,38 @@ } }, "node_modules/date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } }, "node_modules/date-format": { "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } }, "node_modules/date-now": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==", "dev": true }, "node_modules/dateformat": { "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.4", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -10475,42 +9104,15 @@ }, "node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decode-uri-component": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } @@ -10519,6 +9121,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", "optional": true, "dependencies": { "mimic-response": "^2.0.0" @@ -10529,15 +9132,13 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/default-gateway": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -10547,8 +9148,7 @@ }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -10558,8 +9158,7 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -10574,17 +9173,15 @@ }, "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==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -10599,9 +9196,8 @@ }, "node_modules/define-property": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^0.1.0" }, @@ -10611,9 +9207,8 @@ }, "node_modules/del": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", "dev": true, + "license": "MIT", "dependencies": { "globby": "^5.0.0", "is-path-cwd": "^1.0.0", @@ -10629,9 +9224,8 @@ }, "node_modules/del/node_modules/array-union": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, + "license": "MIT", "dependencies": { "array-uniq": "^1.0.1" }, @@ -10641,18 +9235,16 @@ }, "node_modules/del/node_modules/arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/del/node_modules/globby": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^1.0.1", "arrify": "^1.0.0", @@ -10667,19 +9259,16 @@ }, "node_modules/del/node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/del/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -10689,9 +9278,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -10700,31 +9288,29 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", "optional": true }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/destroy": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -10732,17 +9318,17 @@ }, "node_modules/detect-file": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", "optional": true, "engines": { "node": ">=8" @@ -10750,45 +9336,45 @@ }, "node_modules/detect-node": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/di": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/didyoumean": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/diff": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", - "integrity": "sha512-9wfm3RLzMp/PyTFWuw9liEzdlxsdGixCW0ZTU1XDmtlAkvpVXTPGF8KnfSs0hm3BPbg19OrUPPsRkHXoREpP1g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -10798,15 +9384,13 @@ }, "node_modules/dlv": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dns-packet": { "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -10816,9 +9400,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, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -10828,16 +9411,14 @@ }, "node_modules/doctypes": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/dom-serialize": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, + "license": "MIT", "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -10847,9 +9428,8 @@ }, "node_modules/dom-serializer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -10861,21 +9441,19 @@ }, "node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -10888,9 +9466,8 @@ }, "node_modules/domutils": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -10902,9 +9479,8 @@ }, "node_modules/dot-prop": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, + "license": "MIT", "dependencies": { "is-obj": "^2.0.0" }, @@ -10914,9 +9490,8 @@ }, "node_modules/dotenv": { "version": "16.3.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", - "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -10926,29 +9501,39 @@ }, "node_modules/dotenv-expand": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "license": "MIT" }, "node_modules/ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -10956,21 +9541,18 @@ }, "node_modules/ecc-jsbn/node_modules/jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -10982,38 +9564,33 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.789", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", - "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==", - "dev": true + "version": "1.4.763", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/encodeurl": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/encoding": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -11021,18 +9598,16 @@ }, "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/engine.io": { "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", "dev": true, + "license": "MIT", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -11051,18 +9626,16 @@ }, "node_modules/engine.io-parser": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/enhanced-resolve": { "version": "5.16.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", - "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -11073,9 +9646,8 @@ }, "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" }, @@ -11085,15 +9657,13 @@ }, "node_modules/ent": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "devOptional": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -11103,22 +9673,19 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/err-code": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "license": "MIT" }, "node_modules/errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -11129,8 +9696,6 @@ }, "node_modules/error": { "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", "dev": true, "dependencies": { "string-template": "~0.2.1" @@ -11138,18 +9703,16 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -11206,35 +9769,31 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", - "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", - "dev": true + "version": "1.5.2", + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -11243,14 +9802,16 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -11258,18 +9819,16 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -11284,33 +9843,29 @@ }, "node_modules/es5-shim": { "version": "4.6.7", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", - "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/es6-promise": { "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, + "license": "MIT", "dependencies": { "es6-promise": "^4.0.3" } }, "node_modules/esbuild": { "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", - "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "bin": { "esbuild": "bin/esbuild" @@ -11346,9 +9901,8 @@ }, "node_modules/esbuild-wasm": { "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", - "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==", "dev": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -11356,33 +9910,47 @@ "node": ">=12" } }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/eslint": { "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -11435,9 +10003,8 @@ }, "node_modules/eslint-config-prettier": { "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -11447,9 +10014,8 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -11458,18 +10024,16 @@ }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -11484,18 +10048,16 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -11520,9 +10082,8 @@ }, "node_modules/eslint-plugin-import/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" @@ -11530,18 +10091,16 @@ }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -11551,9 +10110,8 @@ }, "node_modules/eslint-plugin-import/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" }, @@ -11563,15 +10121,13 @@ }, "node_modules/eslint-plugin-import/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint-plugin-jsdoc": { "version": "39.3.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.6.tgz", - "integrity": "sha512-R6dZ4t83qPdMhIOGr7g2QII2pwCjYyKP+z0tPOfO1bbAbQyKC20Y2Rd6z1te86Lq3T7uM8bNo+VD9YFpE8HU/g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@es-joy/jsdoccomment": "~0.31.0", "comment-parser": "1.3.1", @@ -11590,9 +10146,8 @@ }, "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11602,18 +10157,16 @@ }, "node_modules/eslint-plugin-prefer-arrow": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", "dev": true, + "license": "MIT", "peerDependencies": { "eslint": ">=2.0.0" } }, "node_modules/eslint-plugin-prettier": { "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", "dev": true, + "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.8.6" @@ -11641,9 +10194,8 @@ }, "node_modules/eslint-scope": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -11657,9 +10209,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -11669,9 +10220,8 @@ }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -11685,9 +10235,8 @@ }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11700,15 +10249,13 @@ }, "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.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", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -11716,9 +10263,8 @@ }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11732,9 +10278,8 @@ }, "node_modules/eslint/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": { "color-name": "~1.1.4" }, @@ -11744,15 +10289,13 @@ }, "node_modules/eslint/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 + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11762,9 +10305,8 @@ }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -11778,9 +10320,8 @@ }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -11790,9 +10331,8 @@ }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -11805,18 +10345,16 @@ }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -11826,15 +10364,13 @@ }, "node_modules/eslint/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/eslint/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" }, @@ -11844,9 +10380,8 @@ }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11856,9 +10391,8 @@ }, "node_modules/eslint/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, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -11868,9 +10402,8 @@ }, "node_modules/espree": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -11885,9 +10418,8 @@ }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -11898,9 +10430,8 @@ }, "node_modules/esquery": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -11910,9 +10441,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -11922,56 +10452,50 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/eventemitter2": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==" + "dev": true, + "license": "MIT" }, "node_modules/eventemitter3": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11992,17 +10516,15 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/expand-brackets": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -12018,24 +10540,21 @@ }, "node_modules/expand-brackets/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/expand-tilde": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, + "license": "MIT", "dependencies": { "homedir-polyfill": "^1.0.1" }, @@ -12045,14 +10564,12 @@ }, "node_modules/exponential-backoff": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + "license": "Apache-2.0" }, "node_modules/express": { "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12092,27 +10609,24 @@ }, "node_modules/express/node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/express/node_modules/finalhandler": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -12128,15 +10642,13 @@ }, "node_modules/express/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/express/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, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -12146,8 +10658,6 @@ }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -12162,28 +10672,26 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/extend-shallow": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, + "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" }, @@ -12193,8 +10701,7 @@ }, "node_modules/external-editor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -12206,8 +10713,7 @@ }, "node_modules/external-editor/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -12217,8 +10723,7 @@ }, "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==", + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -12228,9 +10733,8 @@ }, "node_modules/extglob": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, + "license": "MIT", "dependencies": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -12247,9 +10751,8 @@ }, "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.0" }, @@ -12259,9 +10762,8 @@ }, "node_modules/extglob/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -12272,29 +10774,25 @@ }, "node_modules/extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "license": "MIT" }, "node_modules/fast-diff": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "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", @@ -12308,30 +10806,26 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/faye-websocket": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, + "license": "MIT", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -12341,8 +10835,7 @@ }, "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -12355,9 +10848,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -12367,14 +10859,12 @@ }, "node_modules/file-saver": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", - "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + "license": "MIT" }, "node_modules/file-sync-cmp": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", - "integrity": "sha512-0k45oWBokCqh2MOexeYKpyqmGKG+8mQ2Wd8iawx+uWd/weWJQAZ6SoPybagdCI4xFisag8iAR77WPm4h3pTfxA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/file-uri-to-path": { "version": "1.0.0", @@ -12385,18 +10875,16 @@ }, "node_modules/filelist": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -12405,10 +10893,9 @@ } }, "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "version": "7.0.1", "devOptional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -12418,9 +10905,8 @@ }, "node_modules/finalhandler": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -12436,24 +10922,21 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, + "license": "MIT", "dependencies": { "common-path-prefix": "^3.0.0", "pkg-dir": "^7.0.0" @@ -12467,9 +10950,8 @@ }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -12483,9 +10965,8 @@ }, "node_modules/findup-sync": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", - "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", "dev": true, + "license": "MIT", "dependencies": { "detect-file": "^1.0.0", "is-glob": "^4.0.3", @@ -12498,9 +10979,8 @@ }, "node_modules/fined": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, + "license": "MIT", "dependencies": { "expand-tilde": "^2.0.2", "is-plain-object": "^2.0.3", @@ -12514,27 +10994,24 @@ }, "node_modules/flagged-respawn": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/flat": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, "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==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -12545,15 +11022,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 + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -12561,6 +11039,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -12572,35 +11051,31 @@ }, "node_modules/font-awesome": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", + "license": "(OFL-1.1 AND MIT)", "engines": { "node": ">=0.10.3" } }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/for-in": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/for-own": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, + "license": "MIT", "dependencies": { "for-in": "^1.0.1" }, @@ -12610,8 +11085,7 @@ }, "node_modules/foreground-child": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -12625,8 +11099,7 @@ }, "node_modules/foreground-child/node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { "node": ">=14" }, @@ -12636,21 +11109,23 @@ }, "node_modules/forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -12659,18 +11134,16 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fraction.js": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -12681,9 +11154,8 @@ }, "node_modules/fragment-cache": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, + "license": "MIT", "dependencies": { "map-cache": "^0.2.2" }, @@ -12693,37 +11165,20 @@ }, "node_modules/fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } + "license": "MIT" }, "node_modules/fs-minipass": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -12733,15 +11188,13 @@ }, "node_modules/fs-monkey": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true + "dev": true, + "license": "Unlicense" }, "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==", - "devOptional": true + "devOptional": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -12759,17 +11212,15 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -12785,9 +11236,8 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12797,6 +11247,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", @@ -12815,9 +11266,8 @@ }, "node_modules/gaze": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, + "license": "MIT", "dependencies": { "globule": "^1.0.0" }, @@ -12827,31 +11277,35 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -12862,27 +11316,37 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stdin": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -12892,9 +11356,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -12909,17 +11372,14 @@ }, "node_modules/get-value": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/getobject": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", - "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true, "engines": { "node": ">=10" @@ -12927,38 +11387,33 @@ }, "node_modules/getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } }, "node_modules/git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-5.0.1.tgz", + "integrity": "sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==", "dev": true, + "license": "MIT", "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "@conventional-changelog/git-client": "^2.6.0", + "meow": "^13.0.0" }, "bin": { - "git-raw-commits": "cli.js" + "git-raw-commits": "src/cli.js" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/glob": { "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", "devOptional": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12976,9 +11431,8 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "devOptional": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -12988,15 +11442,13 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "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==", "devOptional": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13004,9 +11456,8 @@ }, "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==", "devOptional": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13014,29 +11465,36 @@ "node": "*" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, + "license": "MIT", "dependencies": { - "ini": "^1.3.4" + "ini": "4.1.1" }, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-dirs/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/global-modules": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, + "license": "MIT", "dependencies": { "global-prefix": "^1.0.1", "is-windows": "^1.0.1", @@ -13048,9 +11506,8 @@ }, "node_modules/global-prefix": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", "dev": true, + "license": "MIT", "dependencies": { "expand-tilde": "^2.0.2", "homedir-polyfill": "^1.0.1", @@ -13064,15 +11521,13 @@ }, "node_modules/global-prefix/node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -13082,18 +11537,16 @@ }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globalthis": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -13107,9 +11560,8 @@ }, "node_modules/globby": { "version": "11.1.0", - "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", @@ -13127,9 +11579,8 @@ }, "node_modules/globule": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", - "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", "dev": true, + "license": "MIT", "dependencies": { "glob": "~7.1.1", "lodash": "^4.17.21", @@ -13141,9 +11592,8 @@ }, "node_modules/globule/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" @@ -13151,9 +11601,8 @@ }, "node_modules/globule/node_modules/minimatch": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13162,11 +11611,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13174,20 +11624,17 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "license": "ISC" }, "node_modules/graphemer": { "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/grunt": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz", - "integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==", "dev": true, + "license": "MIT", "dependencies": { "dateformat": "~4.6.2", "eventemitter2": "~0.4.13", @@ -13212,9 +11659,8 @@ }, "node_modules/grunt-bump": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/grunt-bump/-/grunt-bump-0.8.0.tgz", - "integrity": "sha512-xih0/NBbmIk6LdVspC/yO2E1ITaghfv8aCmY2S6VQ9rxFpZ8skAL4IMwwESlQZIRES+eK6lQOKgpeFBPV5amRA==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^5.1.0" }, @@ -13227,18 +11673,16 @@ }, "node_modules/grunt-bump/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/grunt-cli": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", - "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, + "license": "MIT", "dependencies": { "grunt-known-options": "~2.0.0", "interpret": "~1.1.0", @@ -13255,9 +11699,8 @@ }, "node_modules/grunt-cli/node_modules/nopt": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -13268,8 +11711,6 @@ }, "node_modules/grunt-coffeelint": { "version": "0.0.16", - "resolved": "https://registry.npmjs.org/grunt-coffeelint/-/grunt-coffeelint-0.0.16.tgz", - "integrity": "sha512-dulo0qxyfN3x9GilJxVj7b7hQT61VIpe8kpk68ftmdbBAwOqCg/bneol9izwwBq7A0G+ZZKaBYHIt73JTebteQ==", "dev": true, "dependencies": { "coffeelint": "^1", @@ -13284,9 +11725,8 @@ }, "node_modules/grunt-contrib-clean": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.0.0.tgz", - "integrity": "sha512-53igYwhP+AUWdIfO1R+L9r4O48FSnA5ImYPWdXUNU+YQruOpprmMb+N74P7fAZLL3w9lsFin4B234NUrWx/RrQ==", "dev": true, + "license": "MIT", "dependencies": { "async": "^1.5.2", "rimraf": "^2.5.1" @@ -13300,10 +11740,8 @@ }, "node_modules/grunt-contrib-clean/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -13313,9 +11751,8 @@ }, "node_modules/grunt-contrib-coffee": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-1.0.0.tgz", - "integrity": "sha512-KTp5xSlelwbyPnB9NBtnYhFl3TayzgJKkvT0x4yLKlLJaGWFMW7AsdPQLSFWralQdxSuTLuHvEKUleU30uHsyw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "~1.0.0", "coffee-script": "~1.10.0", @@ -13331,27 +11768,24 @@ }, "node_modules/grunt-contrib-coffee/node_modules/ansi-regex": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-coffee/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-coffee/node_modules/chalk": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", - "integrity": "sha512-1TE3hpADga5iWinlcCpyhC7fTl9uQumLD8i2jJoJeVg7UbveY5jj7F6uCq8w0hQpSeLhaPn5QFe8e56toMVP1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.0.1", "escape-string-regexp": "^1.0.2", @@ -13365,10 +11799,8 @@ }, "node_modules/grunt-contrib-coffee/node_modules/coffee-script": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", - "integrity": "sha512-ef2EsKe2bCuX3VGXfPCNGqni3wgrL8Bu0tDdY8mUDa+QnDR1GNcsC4QhxwG4az6l5y5W0wKUc1Pn/F3MCyafjg==", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", "dev": true, + "license": "MIT", "bin": { "cake": "bin/cake", "coffee": "bin/coffee" @@ -13379,9 +11811,8 @@ }, "node_modules/grunt-contrib-coffee/node_modules/has-ansi": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", - "integrity": "sha512-XwLzIec2hoj/LW9F3nCcQpEwZ5fDJ1LOc6SAgc0pz79CGiY9zmZhIkbf7OnK+tC36UhpQBa03HPt13QavGoF6Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^1.1.0", "get-stdin": "^4.0.1" @@ -13395,15 +11826,13 @@ }, "node_modules/grunt-contrib-coffee/node_modules/lodash": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", - "integrity": "sha512-JDXk2rxAUY3cHGG9OJfRbhd7zc2feQRdMthkMdqmK19l0+ojybg9ISylGUnmqHtteg/wXH8QudOLN+RKgKNKIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/grunt-contrib-coffee/node_modules/strip-ansi": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", - "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^1.0.0" }, @@ -13416,9 +11845,8 @@ }, "node_modules/grunt-contrib-coffee/node_modules/supports-color": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", - "integrity": "sha512-OHbMkscHFRcNWEcW80fYhCrzAjheSIBwJChpFaBqA6zEz53nxumqi6ukciRb/UA0/v2nDNMk28ce/uBbYRDsng==", "dev": true, + "license": "MIT", "bin": { "supports-color": "cli.js" }, @@ -13428,9 +11856,8 @@ }, "node_modules/grunt-contrib-concat": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", - "integrity": "sha512-QdTmcxe8aim2Z0dFeuSJ+f7fHIeY7PZaTMZxgvosjXwyMhpy2GUR5WHkr12lksHfZVE80v2wUwqF56wyfPUwoQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.0.0", "source-map": "^0.5.3" @@ -13444,27 +11871,24 @@ }, "node_modules/grunt-contrib-concat/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-concat/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-concat/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -13478,18 +11902,16 @@ }, "node_modules/grunt-contrib-concat/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-concat/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -13499,18 +11921,16 @@ }, "node_modules/grunt-contrib-concat/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/grunt-contrib-connect": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-1.0.2.tgz", - "integrity": "sha512-7OPoyfGrpOYzuiRPzGyzWDe/xFcjttXe1ztVSFS8TAVBtpfXeeOV9RiwuyqA4yN1UeOG2Pnpx8s0DcUDAu21Gw==", "dev": true, + "license": "MIT", "dependencies": { "async": "^1.5.2", "connect": "^3.4.0", @@ -13531,9 +11951,8 @@ }, "node_modules/grunt-contrib-copy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", - "integrity": "sha512-gFRFUB0ZbLcjKb67Magz1yOHGBkyU6uL29hiEW1tdQ9gQt72NuMKIy/kS6dsCbV0cZ0maNCb0s6y+uT1FKU7jA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.1.1", "file-sync-cmp": "^0.1.0" @@ -13544,27 +11963,24 @@ }, "node_modules/grunt-contrib-copy/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-copy/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-copy/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -13578,9 +11994,8 @@ }, "node_modules/grunt-contrib-copy/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -13590,18 +12005,16 @@ }, "node_modules/grunt-contrib-copy/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/grunt-contrib-jshint": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.0.0.tgz", - "integrity": "sha512-c16rDqMmtF3sZlz8f9IGd2l9BKoW5FvYbsBHwEZl3HN0KmQ7RbbG+kzTNtfIcDjIrWDjHmSVj7TSQXeqnBHGqw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.1.1", "hooker": "^0.2.3", @@ -13616,27 +12029,24 @@ }, "node_modules/grunt-contrib-jshint/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-jshint/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-contrib-jshint/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -13650,9 +12060,8 @@ }, "node_modules/grunt-contrib-jshint/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -13662,18 +12071,16 @@ }, "node_modules/grunt-contrib-jshint/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/grunt-contrib-watch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", - "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", "dev": true, + "license": "MIT", "dependencies": { "async": "^2.6.0", "gaze": "^1.1.0", @@ -13686,17 +12093,14 @@ }, "node_modules/grunt-contrib-watch/node_modules/async": { "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.17.14" } }, "node_modules/grunt-env": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/grunt-env/-/grunt-env-0.4.4.tgz", - "integrity": "sha512-Sm7edLjXyN8YroVPckd1o55lm11J6lCyWOHRvDzIDpUMMFGPB3cp9NEgo0/HPGd3OzSOZ6jUd+Wyn0CYBeLHCg==", "dev": true, "dependencies": { "ini": "~1.3.0", @@ -13708,25 +12112,22 @@ }, "node_modules/grunt-env/node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/grunt-env/node_modules/lodash": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true, "engines": [ "node", "rhino" - ] + ], + "license": "MIT" }, "node_modules/grunt-html2js": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/grunt-html2js/-/grunt-html2js-0.6.0.tgz", - "integrity": "sha512-A6hJjb904r9dQuUKAmYrwwKJonbZeXD0zMCGCBxMZg3ocE2wbNfCaOcorxIZyKi7i/UaiIvEXpDNukQgO663sw==", "dev": true, + "license": "SEE LICENSE IN LICENSE-MIT", "dependencies": { "chokidar": "^2", "html-minifier": "^3" @@ -13743,9 +12144,8 @@ }, "node_modules/grunt-html2js/node_modules/anymatch": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, + "license": "ISC", "dependencies": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" @@ -13753,9 +12153,8 @@ }, "node_modules/grunt-html2js/node_modules/anymatch/node_modules/normalize-path": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, + "license": "MIT", "dependencies": { "remove-trailing-separator": "^1.0.1" }, @@ -13765,18 +12164,16 @@ }, "node_modules/grunt-html2js/node_modules/binary-extensions": { "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-html2js/node_modules/braces": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, + "license": "MIT", "dependencies": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -13795,10 +12192,8 @@ }, "node_modules/grunt-html2js/node_modules/chokidar": { "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "^2.0.0", "async-each": "^1.0.1", @@ -13818,9 +12213,8 @@ }, "node_modules/grunt-html2js/node_modules/define-property": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -13831,9 +12225,8 @@ }, "node_modules/grunt-html2js/node_modules/fill-range": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, + "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -13848,7 +12241,7 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", "dev": true, "hasInstallScript": true, "optional": true, @@ -13865,9 +12258,8 @@ }, "node_modules/grunt-html2js/node_modules/glob-parent": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -13875,9 +12267,8 @@ }, "node_modules/grunt-html2js/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.0" }, @@ -13887,9 +12278,8 @@ }, "node_modules/grunt-html2js/node_modules/is-binary-path": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^1.0.0" }, @@ -13899,9 +12289,8 @@ }, "node_modules/grunt-html2js/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -13912,9 +12301,8 @@ }, "node_modules/grunt-html2js/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -13924,9 +12312,8 @@ }, "node_modules/grunt-html2js/node_modules/is-number": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^3.0.2" }, @@ -13936,9 +12323,8 @@ }, "node_modules/grunt-html2js/node_modules/is-number/node_modules/kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -13948,15 +12334,13 @@ }, "node_modules/grunt-html2js/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/grunt-html2js/node_modules/micromatch": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, + "license": "MIT", "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -13978,9 +12362,8 @@ }, "node_modules/grunt-html2js/node_modules/micromatch/node_modules/extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "license": "MIT", "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -13991,9 +12374,8 @@ }, "node_modules/grunt-html2js/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14006,9 +12388,8 @@ }, "node_modules/grunt-html2js/node_modules/readdirp": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.1.11", "micromatch": "^3.1.10", @@ -14020,18 +12401,16 @@ }, "node_modules/grunt-html2js/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/grunt-html2js/node_modules/to-regex-range": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" @@ -14042,9 +12421,8 @@ }, "node_modules/grunt-karma": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-karma/-/grunt-karma-2.0.0.tgz", - "integrity": "sha512-/5plsdrES8dWrGhg33Q7AiYU1PUHXtMcZLP2pAppUJJKNmCpiGZXpVfHZ7KO19buVxb555UFbfhhbY7FccXH4g==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^3.10.1" }, @@ -14055,24 +12433,21 @@ }, "node_modules/grunt-karma/node_modules/lodash": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/grunt-known-options": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", - "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-legacy-log": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", - "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", "dev": true, + "license": "MIT", "dependencies": { "colors": "~1.1.2", "grunt-legacy-log-utils": "~2.1.0", @@ -14085,9 +12460,8 @@ }, "node_modules/grunt-legacy-log-utils": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", - "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "~4.1.0", "lodash": "~4.17.19" @@ -14098,9 +12472,8 @@ }, "node_modules/grunt-legacy-log-utils/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -14113,9 +12486,8 @@ }, "node_modules/grunt-legacy-log-utils/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14129,9 +12501,8 @@ }, "node_modules/grunt-legacy-log-utils/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": { "color-name": "~1.1.4" }, @@ -14141,24 +12512,21 @@ }, "node_modules/grunt-legacy-log-utils/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 + "dev": true, + "license": "MIT" }, "node_modules/grunt-legacy-log-utils/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/grunt-legacy-log-utils/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -14168,9 +12536,8 @@ }, "node_modules/grunt-legacy-util": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", - "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, + "license": "MIT", "dependencies": { "async": "~3.2.0", "exit": "~0.1.2", @@ -14186,21 +12553,18 @@ }, "node_modules/grunt-legacy-util/node_modules/async": { "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/grunt-legacy-util/node_modules/sprintf-js": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/grunt-legacy-util/node_modules/underscore.string": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", - "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "^1.1.1", "util-deprecate": "^1.0.2" @@ -14209,22 +12573,10 @@ "node": "*" } }, - "node_modules/grunt-lib-contrib": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz", - "integrity": "sha512-HdCtJuMmmkSAVrAfsG7lZWE0YabrsPWwzcCCUgWQOAaQsQSUNhw/IwD2YjCSLh5y9NXSPzHTYFLL4ro7QbAJMA==", - "dependencies": { - "zlib-browserify": "0.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/grunt-newer": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/grunt-newer/-/grunt-newer-1.3.0.tgz", - "integrity": "sha512-HEbcE3pTueSx2IT/WR9F/pJaGioy1+bDu0RPS1JZn8cPHaAGc8BIkcbEHato9Bhoy6ip1R43wY4gfgO6d7utnA==", "dev": true, + "license": "MIT", "dependencies": { "async": "^1.5.2", "rimraf": "^2.5.2" @@ -14238,10 +12590,8 @@ }, "node_modules/grunt-newer/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -14251,10 +12601,8 @@ }, "node_modules/grunt-ng-annotate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/grunt-ng-annotate/-/grunt-ng-annotate-3.0.0.tgz", - "integrity": "sha512-kmmwAyix4OMEOlWvgh584JdVj2tYK6UcsAuS3cbeGuNzYL054hU9zsth+ZuAYslIZPQeZDzW4vTd3KEiF4iBUw==", - "deprecated": "grunt-ng-annotate is deprecated. Switch to babel-plugin-angularjs-annotate or provide annotations by yourself.", "dev": true, + "license": "MIT", "dependencies": { "lodash.clonedeep": "^4.5.0", "ng-annotate": "^1.2.1" @@ -14268,9 +12616,8 @@ }, "node_modules/grunt-postcss": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/grunt-postcss/-/grunt-postcss-0.8.0.tgz", - "integrity": "sha512-Y/GlBwlSXET86uudGM6Sn5Qtjas5PT2AwjMGqKNnSaoxJSfhNY4chpAnOs72VQ4y3LqrP0y5f/i7CroyZqsuJA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.0.0", "diff": "^2.0.2", @@ -14285,27 +12632,24 @@ }, "node_modules/grunt-postcss/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-postcss/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-postcss/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -14319,18 +12663,16 @@ }, "node_modules/grunt-postcss/node_modules/has-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-postcss/node_modules/postcss": { "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.1.3", "js-base64": "^2.1.9", @@ -14343,9 +12685,8 @@ }, "node_modules/grunt-postcss/node_modules/postcss/node_modules/supports-color": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^1.0.0" }, @@ -14355,18 +12696,16 @@ }, "node_modules/grunt-postcss/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/grunt-postcss/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -14376,17 +12715,14 @@ }, "node_modules/grunt-postcss/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/grunt-preprocess": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/grunt-preprocess/-/grunt-preprocess-5.1.0.tgz", - "integrity": "sha512-akQU6U8ULt8gLC6yeGFSBqWQUAqMQPFMm0jAIL4FVIIEkzp3unjDUxu/ZBpbJhiQ9i4IP1M1S6wsdMjE0QsrhQ==", "dev": true, "dependencies": { "lodash": "^4.5.0", @@ -14404,9 +12740,8 @@ }, "node_modules/grunt-sass": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-3.1.0.tgz", - "integrity": "sha512-90s27H7FoCDcA8C8+R0GwC+ntYD3lG6S/jqcavWm3bn9RiJTmSfOvfbFa1PXx4NbBWuiGQMLfQTj/JvvqT5w6A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -14416,9 +12751,8 @@ }, "node_modules/grunt-sass-globbing": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/grunt-sass-globbing/-/grunt-sass-globbing-1.5.1.tgz", - "integrity": "sha512-v1b+xQYGen1uRZ+LSZCVHfYR5JhSlsjT/F9sSatzxKh0vn65wZ0kA5OLta/l8o+uL036oJluqkqSWJRV0k7kUQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10.0" }, @@ -14428,9 +12762,8 @@ }, "node_modules/grunt/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" @@ -14438,9 +12771,8 @@ }, "node_modules/grunt/node_modules/minimatch": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -14450,25 +12782,21 @@ }, "node_modules/handle-thing": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, + "license": "ISC", "engines": { "node": ">=4" } }, "node_modules/har-validator": { "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -14479,9 +12807,8 @@ }, "node_modules/har-validator/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14495,33 +12822,21 @@ }, "node_modules/har-validator/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/has": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4.0" } }, "node_modules/has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -14531,35 +12846,31 @@ }, "node_modules/has-ansi/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/has-bigints": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -14569,8 +12880,8 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -14579,9 +12890,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -14591,9 +12903,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -14608,13 +12919,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", "optional": true }, "node_modules/has-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, + "license": "MIT", "dependencies": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -14626,9 +12937,8 @@ }, "node_modules/has-values": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -14639,9 +12949,8 @@ }, "node_modules/has-values/node_modules/is-number": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^3.0.2" }, @@ -14651,9 +12960,8 @@ }, "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -14663,9 +12971,8 @@ }, "node_modules/has-values/node_modules/kind-of": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -14675,8 +12982,7 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -14686,18 +12992,16 @@ }, "node_modules/he": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } }, "node_modules/homedir-polyfill": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, + "license": "MIT", "dependencies": { "parse-passwd": "^1.0.0" }, @@ -14707,47 +13011,15 @@ }, "node_modules/hooker": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", - "engines": { - "node": "*" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "*" } }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/hpack.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -14757,15 +13029,13 @@ }, "node_modules/hpack.js/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14778,17 +13048,14 @@ }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/html-entities": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -14799,19 +13066,18 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/html-minifier": { "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "dev": true, + "license": "MIT", "dependencies": { "camel-case": "3.0.x", "clean-css": "4.2.x", @@ -14830,14 +13096,30 @@ }, "node_modules/html-minifier/node_modules/commander": { "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/html5-qrcode": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz", + "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==", + "license": "Apache-2.0" }, "node_modules/htmlparser2": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -14846,6 +13128,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -14855,20 +13138,17 @@ }, "node_modules/http-cache-semantics": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -14882,24 +13162,21 @@ }, "node_modules/http-errors/node_modules/statuses": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/http-parser-js": { "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -14911,8 +13188,7 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -14923,9 +13199,8 @@ }, "node_modules/http-proxy-middleware": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -14947,9 +13222,8 @@ }, "node_modules/http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -14962,18 +13236,15 @@ }, "node_modules/http2": { "version": "3.3.7", - "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", - "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", - "deprecated": "Use the built-in module in node 9.0.0 or newer, instead", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0 <9.0.0" } }, "node_modules/https-proxy-agent": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -14984,18 +13255,16 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/husky": { "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", "dev": true, + "license": "MIT", "bin": { "husky": "lib/bin.js" }, @@ -15008,9 +13277,8 @@ }, "node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "devOptional": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -15020,9 +13288,8 @@ }, "node_modules/icss-utils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -15032,8 +13299,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -15047,21 +13312,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "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==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/ignore-walk": { "version": "6.0.5", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", - "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "license": "ISC", "dependencies": { "minimatch": "^9.0.0" }, @@ -15071,9 +13335,8 @@ }, "node_modules/image-size": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -15084,21 +13347,19 @@ }, "node_modules/immediate": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true + "license": "MIT" }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", - "dev": true + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", + "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -15112,35 +13373,41 @@ }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", "engines": { "node": ">=8" } }, "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.", "devOptional": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -15148,21 +13415,18 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "license": "ISC" }, "node_modules/ini": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/inquirer": { "version": "9.2.15", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", - "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "license": "MIT", "dependencies": { "@ljharb/through": "^2.3.12", "ansi-escapes": "^4.3.2", @@ -15186,8 +13450,7 @@ }, "node_modules/inquirer/node_modules/chalk": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -15195,19 +13458,10 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/internal-slot": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -15219,20 +13473,17 @@ }, "node_modules/interpret": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ip": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ip-address": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -15243,23 +13494,20 @@ }, "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/is-absolute": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, + "license": "MIT", "dependencies": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" @@ -15270,9 +13518,8 @@ }, "node_modules/is-accessor-descriptor": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -15282,9 +13529,8 @@ }, "node_modules/is-array-buffer": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -15298,15 +13544,13 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-bigint": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -15316,9 +13560,8 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "devOptional": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -15328,9 +13571,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -15344,15 +13586,13 @@ }, "node_modules/is-buffer": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -15362,8 +13602,7 @@ }, "node_modules/is-core-module": { "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -15373,9 +13612,8 @@ }, "node_modules/is-data-descriptor": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -15385,9 +13623,8 @@ }, "node_modules/is-data-view": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" }, @@ -15400,9 +13637,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -15415,9 +13651,8 @@ }, "node_modules/is-descriptor": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -15428,8 +13663,7 @@ }, "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==", + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -15442,9 +13676,8 @@ }, "node_modules/is-expression": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", - "integrity": "sha512-vyMeQMq+AiH5uUnoBfMTwf18tO3bM6k1QXBE9D6ueAAquEfCZe3AJPtud9g6qS0+4X8xA7ndpZiDyeb2l2qOBw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "acorn": "~4.0.2", @@ -15453,9 +13686,8 @@ }, "node_modules/is-expression/node_modules/acorn": { "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", "dev": true, + "license": "MIT", "optional": true, "bin": { "acorn": "bin/acorn" @@ -15466,35 +13698,31 @@ }, "node_modules/is-extendable": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "devOptional": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -15504,22 +13732,19 @@ }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-lambda": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + "license": "MIT" }, "node_modules/is-negative-zero": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -15529,18 +13754,16 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -15553,27 +13776,24 @@ }, "node_modules/is-obj": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-path-cwd": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-path-in-cwd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, + "license": "MIT", "dependencies": { "is-path-inside": "^1.0.0" }, @@ -15583,9 +13803,8 @@ }, "node_modules/is-path-in-cwd/node_modules/is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", "dev": true, + "license": "MIT", "dependencies": { "path-is-inside": "^1.0.1" }, @@ -15595,18 +13814,16 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-plain-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -15616,9 +13833,8 @@ }, "node_modules/is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -15628,16 +13844,14 @@ }, "node_modules/is-promise": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/is-regex": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -15651,9 +13865,8 @@ }, "node_modules/is-relative": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, + "license": "MIT", "dependencies": { "is-unc-path": "^1.0.0" }, @@ -15663,9 +13876,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -15678,9 +13890,8 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -15690,9 +13901,8 @@ }, "node_modules/is-string": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -15705,9 +13915,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -15718,23 +13927,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", - "dev": true, - "dependencies": { - "text-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-typed-array": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" }, @@ -15747,15 +13943,13 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unc-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, + "license": "MIT", "dependencies": { "unc-path-regex": "^0.1.2" }, @@ -15765,8 +13959,7 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -15776,9 +13969,8 @@ }, "node_modules/is-weakref": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -15788,23 +13980,20 @@ }, "node_modules/is-what": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-windows": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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==", + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -15814,15 +14003,13 @@ }, "node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isbinaryfile": { "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8.0.0" }, @@ -15832,38 +14019,33 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -15877,18 +14059,16 @@ }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -15900,18 +14080,16 @@ }, "node_modules/istanbul-lib-report/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -15921,9 +14099,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^2.0.5", @@ -15937,18 +14114,16 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=6" } }, "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -15959,19 +14134,16 @@ }, "node_modules/istanbul-lib-source-maps/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", "engines": { "node": ">=6" } }, "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -15981,27 +14153,24 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul-reports": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -16011,9 +14180,8 @@ } }, "node_modules/jackspeak": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.2.3.tgz", - "integrity": "sha512-htOzIMPbpLid/Gq9/zaz9SfExABxqRe1sSCdxntlO/aMD6u0issZQiY25n2GKQUtJ02j7z5sfptlAOMpWWOmvw==", + "version": "2.3.6", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -16029,9 +14197,8 @@ }, "node_modules/jake": { "version": "10.9.1", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", - "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -16047,9 +14214,8 @@ }, "node_modules/jake/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16062,15 +14228,13 @@ }, "node_modules/jake/node_modules/async": { "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jake/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" @@ -16078,9 +14242,8 @@ }, "node_modules/jake/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16094,9 +14257,8 @@ }, "node_modules/jake/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": { "color-name": "~1.1.4" }, @@ -16106,24 +14268,21 @@ }, "node_modules/jake/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 + "dev": true, + "license": "MIT" }, "node_modules/jake/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jake/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" }, @@ -16133,9 +14292,8 @@ }, "node_modules/jake/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -16145,9 +14303,8 @@ }, "node_modules/jasmine": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", "dev": true, + "license": "MIT", "dependencies": { "exit": "^0.1.2", "glob": "^7.0.6", @@ -16159,48 +14316,42 @@ }, "node_modules/jasmine-core": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.1.1.tgz", - "integrity": "sha512-lmUfT5XcK9KKvt3lLYzn93hc4MGzlUBowExFVgzbSW0ZCrdeyS574dfsyfRhxbg81Wj4gk+RxUiTnj7KBfDA1g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jasmine-spec-reporter": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", - "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "colors": "1.4.0" } }, "node_modules/jasmine-spec-reporter/node_modules/colors": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/jasmine/node_modules/jasmine-core": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jasminewd2": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6.9.x" } }, "node_modules/jest-diff": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -16213,9 +14364,8 @@ }, "node_modules/jest-diff/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16228,9 +14378,8 @@ }, "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16244,9 +14393,8 @@ }, "node_modules/jest-diff/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": { "color-name": "~1.1.4" }, @@ -16256,24 +14404,21 @@ }, "node_modules/jest-diff/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 + "dev": true, + "license": "MIT" }, "node_modules/jest-diff/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -16283,18 +14428,16 @@ }, "node_modules/jest-get-type": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -16306,18 +14449,16 @@ }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -16330,42 +14471,35 @@ }, "node_modules/jiti": { "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, "node_modules/jquery": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.1.4.tgz", - "integrity": "sha512-wWR+eCq/T/Qt0NcFyM+QVho0ZVzWxFYANijmSMImXiM5mjr1aOaf4SF0eOEPc92bbK2L2vDpxw3lIszus7eO8Q==" + "version": "2.1.4" }, "node_modules/js-base64": { "version": "2.6.4", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", - "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/js-stringify": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "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" @@ -16376,23 +14510,20 @@ }, "node_modules/jsbn": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.0.0" } }, "node_modules/jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -16402,9 +14533,8 @@ }, "node_modules/jshint": { "version": "2.9.7", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", - "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", "dev": true, + "license": "(MIT AND JSON)", "dependencies": { "cli": "~1.0.0", "console-browserify": "1.1.x", @@ -16421,9 +14551,8 @@ }, "node_modules/jshint/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" @@ -16431,9 +14560,8 @@ }, "node_modules/jshint/node_modules/dom-serializer": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "entities": "^2.0.0" @@ -16441,35 +14569,30 @@ }, "node_modules/jshint/node_modules/dom-serializer/node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/jshint/node_modules/dom-serializer/node_modules/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/jshint/node_modules/domelementtype": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/jshint/node_modules/domhandler": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", "dev": true, "dependencies": { "domelementtype": "1" @@ -16477,8 +14600,6 @@ }, "node_modules/jshint/node_modules/domutils": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", "dev": true, "dependencies": { "dom-serializer": "0", @@ -16487,15 +14608,13 @@ }, "node_modules/jshint/node_modules/entities": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", - "dev": true + "dev": true, + "license": "BSD-like" }, "node_modules/jshint/node_modules/htmlparser2": { "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "1", "domhandler": "2.3", @@ -16506,15 +14625,13 @@ }, "node_modules/jshint/node_modules/isarray": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jshint/node_modules/minimatch": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -16524,9 +14641,8 @@ }, "node_modules/jshint/node_modules/readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -16536,15 +14652,13 @@ }, "node_modules/jshint/node_modules/string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jshint/node_modules/strip-json-comments": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", "dev": true, + "license": "MIT", "bin": { "strip-json-comments": "cli.js" }, @@ -16554,52 +14668,44 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", - "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -16609,14 +14715,12 @@ }, "node_modules/jsonc-parser": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + "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" }, @@ -16626,33 +14730,15 @@ }, "node_modules/jsonparse": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "engines": [ "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } + ], + "license": "MIT" }, "node_modules/jsprim": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -16665,9 +14751,8 @@ }, "node_modules/jstransformer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", - "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "is-promise": "^2.0.0", @@ -16678,7 +14763,7 @@ "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -16688,15 +14773,11 @@ }, "node_modules/jszip/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "license": "MIT" }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16709,18 +14790,15 @@ }, "node_modules/jszip/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/karma": { "version": "6.4.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", - "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", "dev": true, + "license": "MIT", "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -16756,18 +14834,16 @@ }, "node_modules/karma-chrome-launcher": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", - "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, + "license": "MIT", "dependencies": { "which": "^1.2.1" } }, "node_modules/karma-chrome-launcher/node_modules/which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -16777,9 +14853,8 @@ }, "node_modules/karma-coverage-istanbul-reporter": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", "dev": true, + "license": "MIT", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-report": "^3.0.0", @@ -16793,9 +14868,8 @@ }, "node_modules/karma-coverage-istanbul-reporter/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" @@ -16803,9 +14877,8 @@ }, "node_modules/karma-coverage-istanbul-reporter/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" }, @@ -16815,9 +14888,8 @@ }, "node_modules/karma-jasmine": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", - "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", "dev": true, + "license": "MIT", "dependencies": { "jasmine-core": "^3.6.0" }, @@ -16830,9 +14902,8 @@ }, "node_modules/karma-jasmine-html-reporter": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", - "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", "dev": true, + "license": "MIT", "peerDependencies": { "jasmine-core": ">=3.8", "karma": ">=0.9", @@ -16841,24 +14912,21 @@ }, "node_modules/karma-jasmine/node_modules/jasmine-core": { "version": "3.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", - "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/karma-source-map-support": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", "dev": true, + "license": "MIT", "dependencies": { "source-map-support": "^0.5.5" } }, "node_modules/karma/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16871,9 +14939,8 @@ }, "node_modules/karma/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" @@ -16881,9 +14948,8 @@ }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -16892,9 +14958,8 @@ }, "node_modules/karma/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": { "color-name": "~1.1.4" }, @@ -16904,15 +14969,13 @@ }, "node_modules/karma/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 + "dev": true, + "license": "MIT" }, "node_modules/karma/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" }, @@ -16922,18 +14985,16 @@ }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/karma/node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -16948,9 +15009,8 @@ }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -16966,45 +15026,40 @@ }, "node_modules/karma/node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/klona": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/launch-editor": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -17012,9 +15067,8 @@ }, "node_modules/lazy-cache": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -17022,9 +15076,8 @@ }, "node_modules/less": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -17048,9 +15101,8 @@ }, "node_modules/less-loader": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4" }, @@ -17068,9 +15120,8 @@ }, "node_modules/less/node_modules/make-dir": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pify": "^4.0.1", @@ -17082,9 +15133,8 @@ }, "node_modules/less/node_modules/mime": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "optional": true, "bin": { "mime": "cli.js" @@ -17095,9 +15145,8 @@ }, "node_modules/less/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", "optional": true, "engines": { "node": ">=6" @@ -17105,9 +15154,8 @@ }, "node_modules/less/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "optional": true, "bin": { "semver": "bin/semver" @@ -17115,9 +15163,8 @@ }, "node_modules/less/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -17125,9 +15172,8 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -17138,9 +15184,8 @@ }, "node_modules/license-webpack-plugin": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, + "license": "ISC", "dependencies": { "webpack-sources": "^3.0.0" }, @@ -17155,18 +15200,15 @@ }, "node_modules/lie": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } }, "node_modules/liftup": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", - "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", "dev": true, + "license": "MIT", "dependencies": { "extend": "^3.0.2", "findup-sync": "^4.0.0", @@ -17183,9 +15225,8 @@ }, "node_modules/liftup/node_modules/findup-sync": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, + "license": "MIT", "dependencies": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", @@ -17198,33 +15239,29 @@ }, "node_modules/lilconfig": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "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==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/livereload-js": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", - "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/load-grunt-tasks": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-5.1.0.tgz", - "integrity": "sha512-oNj0Jlka1TsfDe+9He0kcA1cRln+TMoTsEByW7ij6kyktNLxBKJtslCFEvFrLC2Dj0S19IWJh3fOCIjLby2Xrg==", "dev": true, + "license": "MIT", "dependencies": { "arrify": "^2.0.1", "multimatch": "^4.0.0", @@ -17240,9 +15277,8 @@ }, "node_modules/load-json-file": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -17255,9 +15291,8 @@ }, "node_modules/load-json-file/node_modules/parse-json": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, + "license": "MIT", "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -17268,27 +15303,24 @@ }, "node_modules/loader-runner": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" } }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -17301,31 +15333,68 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -17339,8 +15408,7 @@ }, "node_modules/log-symbols/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -17353,8 +15421,7 @@ }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -17368,8 +15435,7 @@ }, "node_modules/log-symbols/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -17379,21 +15445,18 @@ }, "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/log-symbols/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==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/log-symbols/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==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -17403,9 +15466,8 @@ }, "node_modules/log4js": { "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -17419,38 +15481,35 @@ }, "node_modules/longest": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/lottie-web": { - "version": "5.12.2", - "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", - "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz", + "integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==", + "license": "MIT" }, "node_modules/lower-case": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/magic-string": { "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -17460,9 +15519,8 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -17475,14 +15533,12 @@ }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -17503,17 +15559,15 @@ }, "node_modules/make-fetch-happen/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/make-iterator": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -17523,30 +15577,16 @@ }, "node_modules/map-cache": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/map-visit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, + "license": "MIT", "dependencies": { "object-visit": "^1.0.0" }, @@ -17556,8 +15596,7 @@ }, "node_modules/marked": { "version": "11.2.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", - "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "license": "MIT", "bin": { "marked": "bin/marked.js" }, @@ -17565,20 +15604,27 @@ "node": ">= 18" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, + "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" }, @@ -17588,96 +15634,56 @@ }, "node_modules/memorystream": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, "engines": { "node": ">= 0.10.0" } }, "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "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.5", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.3", + "braces": "^3.0.2", "picomatch": "^2.3.1" }, "engines": { @@ -17686,9 +15692,8 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -17698,9 +15703,8 @@ }, "node_modules/mime": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -17710,18 +15714,16 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -17731,8 +15733,7 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -17741,6 +15742,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -17749,20 +15751,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", - "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", "dev": true, + "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -17780,14 +15772,12 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "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.4", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -17800,57 +15790,22 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minimist-options/node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minimist-options/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.1", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-collect": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -17860,8 +15815,7 @@ }, "node_modules/minipass-fetch": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -17876,8 +15830,7 @@ }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -17887,8 +15840,7 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -17898,13 +15850,11 @@ }, "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/minipass-json-stream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "license": "MIT", "dependencies": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -17912,8 +15862,7 @@ }, "node_modules/minipass-json-stream/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -17923,13 +15872,11 @@ }, "node_modules/minipass-json-stream/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -17939,8 +15886,7 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -17950,13 +15896,11 @@ }, "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -17966,8 +15910,7 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -17977,13 +15920,11 @@ }, "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/minizlib": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -17994,8 +15935,7 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -18005,14 +15945,12 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/mixin-deep": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, + "license": "MIT", "dependencies": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -18023,9 +15961,8 @@ }, "node_modules/mixin-deep/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -18035,9 +15972,8 @@ }, "node_modules/mkdirp": { "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -18047,17 +15983,21 @@ }, "node_modules/moment": { "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", "engines": { "node": "*" } }, + "node_modules/monaco-editor": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", + "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==", + "license": "MIT" + }, "node_modules/morgan": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, + "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -18071,38 +16011,33 @@ }, "node_modules/morgan/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/morgan/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mrmime": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -18113,9 +16048,8 @@ }, "node_modules/multimatch": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/minimatch": "^3.0.3", "array-differ": "^3.0.0", @@ -18129,9 +16063,8 @@ }, "node_modules/multimatch/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" @@ -18139,9 +16072,8 @@ }, "node_modules/multimatch/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" }, @@ -18151,17 +16083,15 @@ }, "node_modules/mute-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/mz": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -18169,15 +16099,13 @@ } }, "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", "optional": true }, "node_modules/nanoid": { "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -18185,6 +16113,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -18194,9 +16123,8 @@ }, "node_modules/nanomatch": { "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, + "license": "MIT", "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -18216,9 +16144,8 @@ }, "node_modules/nanomatch/node_modules/define-property": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -18229,9 +16156,8 @@ }, "node_modules/nanomatch/node_modules/extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "license": "MIT", "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -18242,9 +16168,8 @@ }, "node_modules/nanomatch/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -18255,9 +16180,8 @@ }, "node_modules/nanomatch/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -18267,15 +16191,13 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/needle": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.3", @@ -18290,23 +16212,20 @@ }, "node_modules/negotiator": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ng-annotate": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ng-annotate/-/ng-annotate-1.2.2.tgz", - "integrity": "sha512-bExxD+wmtr38NwfFoeAsLqFZvliBPy+H1jz2tZveEoFrmmP4uFmWmMaJSFcO/5Kry6Is1WaXfpXiFQtK0T8tWQ==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "~2.6.4", "alter": "~0.2.0", @@ -18327,9 +16246,8 @@ }, "node_modules/ng-annotate/node_modules/acorn": { "version": "2.6.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz", - "integrity": "sha512-aINieSoQYX0C9uQqJGeC8mnO1T6onBTmtCdxHel6ZP/nBu4mpC03EoDtQUzAAAlUXluWjIvVV9vCuMhmOdRDXQ==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -18339,36 +16257,30 @@ }, "node_modules/ng-annotate/node_modules/convert-source-map": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ng-annotate/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/ng-csv": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ng-csv/-/ng-csv-0.2.3.tgz", - "integrity": "sha512-Hr+Y6IRCzgNqlVvIO00TMDdAeOD7z/3ishxvFfj9+xxW/+CLZnFZzYC9djKDyEPxDmmMqkdRcqwfsM+e+CBNRw==", "engines": { "node": ">=0.8.0" } }, "node_modules/ng-file-upload": { "version": "5.0.9", - "resolved": "https://registry.npmjs.org/ng-file-upload/-/ng-file-upload-5.0.9.tgz", - "integrity": "sha512-298k/s42+cyHLFAWCtgmXHGOUFqAh5VviSbMuQAPfqAavK1h9ADU/A+gN7OLmgNhW9PM94bWSt22LpjO/cvKwA==" + "license": "MIT" }, "node_modules/ng-flex-layout": { - "version": "17.3.4-beta.1", - "resolved": "https://registry.npmjs.org/ng-flex-layout/-/ng-flex-layout-17.3.4-beta.1.tgz", - "integrity": "sha512-MmXj7Cq9cBSDgJKT3vOok2YCq3OcUD4zhPaKup9V5lVJLZ38sHPgfPf5fFBjDZO7R6AD66wYPod0i4zW5LrrgA==", + "version": "17.3.7-beta.1", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -18382,8 +16294,7 @@ }, "node_modules/ng2-pdf-viewer": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.2.2.tgz", - "integrity": "sha512-GaKAvF0nXAiR9U4LFWuT54MM9nzp0ie8GGscp34W+lFsSOXdlwS0iFx5UPuVlODRm3YEUKx6xcK5oaJeBq0SAw==", + "license": "MIT", "dependencies": { "pdfjs-dist": "^3.11.174", "tslib": "^2.3.0" @@ -18391,17 +16302,16 @@ }, "node_modules/ngx-bootstrap": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-6.2.0.tgz", - "integrity": "sha512-5WKHo6/ltkenw4UyXZwED8rODCgp2RGbWurzYzZsF/gH1JO5SN7TJ+AL6kXYk6XM42sDA2WhN9Db+ZPNjiyHnA==", + "license": "MIT", "peerDependencies": { "@angular/common": ">=7.0.0", "@angular/core": ">=7.0.0" } }, "node_modules/ngx-entity-service": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.39.tgz", - "integrity": "sha512-81DdRQxN7R2lELTiZkB5FkjeK147C8AUmyl52sxZgtYw/WiFay7iWk9KTSsZAJ8OhKKkmllXfMkOpQzvoYTafw==", + "version": "0.0.41", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.41.tgz", + "integrity": "sha512-rf3gZQr4CthXV34WKySg200c06ZuXm2Z7EclUR6bAuiuvUDwRAPMEAJmtSmDyYbnpQqLMMb+5rfaQQakkTNotA==", "dependencies": { "tslib": "^2.3.0" }, @@ -18412,8 +16322,7 @@ }, "node_modules/ngx-lottie": { "version": "11.0.2", - "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-11.0.2.tgz", - "integrity": "sha512-sQhCTxfrzWpjN2HVFCSyAQYQg8ZjZVtO1xIhOkrJNHY3/TR/zZkVrhakWcaM5bVxyA7gfUnK3ox+iK59Yd8Bsw==", + "license": "MIT", "dependencies": { "@scarf/scarf": "^1.1.1", "tslib": "^2.3.0" @@ -18423,12 +16332,25 @@ "lottie-web": ">=5.9.2" } }, + "node_modules/ngx-monaco-editor-v2": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2/-/ngx-monaco-editor-v2-17.0.1.tgz", + "integrity": "sha512-GP+Ni6zKFQjF/ve5ZQtfE9eRLKL4GxMvdmDTrla1x6F5pSIcYGCcjZ4gQ1/AHMa5dgarfs+Et+1bBtAOJtI6KA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.3", + "@angular/core": "^17.0.3", + "monaco-editor": "^0.44.0" + } + }, "node_modules/nice-napi": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "!win32" @@ -18438,32 +16360,25 @@ "node-gyp-build": "^4.2.2" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/no-case": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^1.1.1" } }, "node_modules/node-addon-api": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "optional": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -18481,18 +16396,18 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-gyp": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", - "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", @@ -18514,9 +16429,8 @@ }, "node_modules/node-gyp-build": { "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", "dev": true, + "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -18526,22 +16440,20 @@ }, "node_modules/node-gyp/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.3.15", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -18555,30 +16467,14 @@ }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", "engines": { "node": ">=16" } }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "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/nopt": { "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "license": "ISC", "dependencies": { "abbrev": "^2.0.0" }, @@ -18591,8 +16487,7 @@ }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -18605,21 +16500,18 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nopt": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1" }, @@ -18627,43 +16519,25 @@ "nopt": "bin/nopt.js" } }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/npm-bundled": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", - "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "license": "ISC", "dependencies": { "npm-normalize-package-bin": "^3.0.0" }, @@ -18673,8 +16547,7 @@ }, "node_modules/npm-install-checks": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" }, @@ -18684,16 +16557,14 @@ }, "node_modules/npm-normalize-package-bin": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-package-arg": { "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "license": "ISC", "dependencies": { "hosted-git-info": "^7.0.0", "proc-log": "^3.0.0", @@ -18706,8 +16577,7 @@ }, "node_modules/npm-package-arg/node_modules/hosted-git-info": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -18717,16 +16587,14 @@ }, "node_modules/npm-package-arg/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/npm-packlist": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "license": "ISC", "dependencies": { "ignore-walk": "^6.0.4" }, @@ -18736,8 +16604,7 @@ }, "node_modules/npm-pick-manifest": { "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", - "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "license": "ISC", "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", @@ -18750,8 +16617,7 @@ }, "node_modules/npm-registry-fetch": { "version": "16.2.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", - "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "license": "ISC", "dependencies": { "@npmcli/redact": "^1.1.0", "make-fetch-happen": "^13.0.0", @@ -18768,131 +16634,120 @@ }, "node_modules/npm-registry-fetch/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==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "node_modules/npm-run-all2": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.2.tgz", + "integrity": "sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.6", "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^4.0.0", + "shell-quote": "^1.7.3", + "which": "^5.0.0" }, "bin": { "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">= 4" + "node": "^18.17.0 || >=20.5.0", + "npm": ">= 9" } }, - "node_modules/npm-run-all/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==", + "node_modules/npm-run-all2/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/npm-run-all2/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, "engines": { - "node": ">=4.8" + "node": ">=16" } }, - "node_modules/npm-run-all/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/npm-run-all2/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/npm-run-all2/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, "engines": { - "node": ">=4" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/npm-run-all2/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, "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.10" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", + "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/npm-run-all2/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { - "which": "bin/which" + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -18905,6 +16760,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", + "license": "ISC", "optional": true, "dependencies": { "are-we-there-yet": "^2.0.0", @@ -18915,9 +16771,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -18927,29 +16782,26 @@ }, "node_modules/num2fraction": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nvd3": { "version": "1.8.6", - "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.6.tgz", - "integrity": "sha512-YGQ9hAQHuQCF0JmYkT2GhNMHb5pA+vDfQj6C2GdpQPzdRPj/srPG3mh/3fZzUFt+at1NusLk/RqICUWkxm4viQ==", + "license": "Apache-2.0", "peerDependencies": { "d3": "^3.4.4" } }, "node_modules/nx": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.1.2.tgz", - "integrity": "sha512-hqD0HglmZCqgPLGcEfLq79El9iBUlinoncmsk6wsPHJM1IrASxHkemJZiehYilQx55QACd1MGBjC2nySZmgyLA==", + "version": "18.3.4", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { - "@nrwl/tao": "19.1.2", + "@nrwl/tao": "18.3.4", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.7", + "@zkochan/js-yaml": "0.0.6", "axios": "^1.6.0", "chalk": "^4.1.0", "cli-cursor": "3.1.0", @@ -18963,6 +16815,7 @@ "fs-extra": "^11.1.0", "ignore": "^5.0.4", "jest-diff": "^29.4.1", + "js-yaml": "4.1.0", "jsonc-parser": "3.2.0", "lines-and-columns": "~2.0.3", "minimatch": "9.0.3", @@ -18985,16 +16838,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.1.2", - "@nx/nx-darwin-x64": "19.1.2", - "@nx/nx-freebsd-x64": "19.1.2", - "@nx/nx-linux-arm-gnueabihf": "19.1.2", - "@nx/nx-linux-arm64-gnu": "19.1.2", - "@nx/nx-linux-arm64-musl": "19.1.2", - "@nx/nx-linux-x64-gnu": "19.1.2", - "@nx/nx-linux-x64-musl": "19.1.2", - "@nx/nx-win32-arm64-msvc": "19.1.2", - "@nx/nx-win32-x64-msvc": "19.1.2" + "@nx/nx-darwin-arm64": "18.3.4", + "@nx/nx-darwin-x64": "18.3.4", + "@nx/nx-freebsd-x64": "18.3.4", + "@nx/nx-linux-arm-gnueabihf": "18.3.4", + "@nx/nx-linux-arm64-gnu": "18.3.4", + "@nx/nx-linux-arm64-musl": "18.3.4", + "@nx/nx-linux-x64-gnu": "18.3.4", + "@nx/nx-linux-x64-musl": "18.3.4", + "@nx/nx-win32-arm64-msvc": "18.3.4", + "@nx/nx-win32-x64-msvc": "18.3.4" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -19010,9 +16863,9 @@ } }, "node_modules/nx/node_modules/@nx/nx-darwin-arm64": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.1.2.tgz", - "integrity": "sha512-YeT/u+r0iZSokbVFsuiFpF/eFAZmR1p6gkpHo6cVIb0KTkH6Sd1n3s1cjfOKEZg+M0emf9Q8QQ6tw41wGrUm4Q==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.3.4.tgz", + "integrity": "sha512-MOGk9z4fIoOkJB68diH3bwoWrC8X9IzMNsz1mu0cbVfgCRAfIV3b+lMsiwQYzWal3UWW5DE5Rkss4F8whiV5Uw==", "cpu": [ "arm64" ], @@ -19026,9 +16879,9 @@ } }, "node_modules/nx/node_modules/@nx/nx-darwin-x64": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.1.2.tgz", - "integrity": "sha512-nmbz/4tgvXwYmxIQptny7Cij0OTAxIdB2l+qmI4tkBnN2mT5UVqdG9t8ziSyZHJbWQjIHTkbgAbg5ar6vK/srA==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.3.4.tgz", + "integrity": "sha512-tSzPRnNB3QdPM+KYiIuRCUtyCwcuIRC95FfP0ZB3WvfDeNxJChEAChNqmCMDE4iFvZhGuze8WqkJuIVdte+lyQ==", "cpu": [ "x64" ], @@ -19042,9 +16895,9 @@ } }, "node_modules/nx/node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.1.2.tgz", - "integrity": "sha512-0XZSz37nrbABUxw2wOMsUP2djsYRxXn1+jbh/kcOH6PnlwiTPOJ6LwDENUh9lZ4PKflED5Tj0w6wx23/AH4z3g==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.3.4.tgz", + "integrity": "sha512-vbHxv7m3gjthBvw50EYCtgyY0Zg5nVTaQtX+wRsmKybV2i7wHbw5zIe1aL4zHUm6TcPGbIQK+utVM+hyCqKHVA==", "cpu": [ "x64" ], @@ -19058,9 +16911,9 @@ } }, "node_modules/nx/node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.1.2", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.1.2.tgz", - "integrity": "sha512-H8ldXwXnVff2A9tDU8AD7QE/uZV06D0gHBdbnrzbg74NOrkKvvUPXky0D6BMlooljkU9QXu7M46CWRNIoPSzQw==", + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.4.tgz", + "integrity": "sha512-/RqEjNU9hxIBxRLafCNKoH3SaB2FShf+1ZnIYCdAoCZBxLJebDpnhiyrVs0lPnMj9248JbizEMdJj1+bs/bXig==", "cpu": [ "x64" ], @@ -19075,9 +16928,8 @@ }, "node_modules/nx/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -19088,11 +16940,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/nx/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, "node_modules/nx/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19106,9 +16962,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -19118,15 +16973,13 @@ }, "node_modules/nx/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 + "dev": true, + "license": "MIT" }, "node_modules/nx/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", @@ -19138,24 +16991,46 @@ }, "node_modules/nx/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/nx/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "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==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/nx/node_modules/minimatch": { + "version": "9.0.3", + "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/nx/node_modules/ora": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.0.3", "chalk": "^4.1.0", @@ -19175,9 +17050,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -19187,9 +17061,8 @@ }, "node_modules/nx/node_modules/tsconfig-paths": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, + "license": "MIT", "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", @@ -19201,27 +17074,24 @@ }, "node_modules/oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "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==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-copy": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, + "license": "MIT", "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -19233,9 +17103,8 @@ }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -19245,36 +17114,32 @@ }, "node_modules/object-hash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/object-inspect": { "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object-visit": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.0" }, @@ -19284,9 +17149,8 @@ }, "node_modules/object.assign": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -19302,9 +17166,8 @@ }, "node_modules/object.defaults": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, + "license": "MIT", "dependencies": { "array-each": "^1.0.1", "array-slice": "^1.0.0", @@ -19317,9 +17180,8 @@ }, "node_modules/object.map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, + "license": "MIT", "dependencies": { "for-own": "^1.0.0", "make-iterator": "^1.0.0" @@ -19330,9 +17192,8 @@ }, "node_modules/object.pick": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -19342,9 +17203,8 @@ }, "node_modules/object.values": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -19359,15 +17219,13 @@ }, "node_modules/obuf": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -19377,26 +17235,23 @@ }, "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==", "devOptional": 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==", + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -19409,8 +17264,7 @@ }, "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==", + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -19425,9 +17279,8 @@ }, "node_modules/opn": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha512-iPBWbPP4OEOzR1xfhpGLDh+ypKBOygunZhM9jBtA7FS5sKjEiMZw0EFb82hnDOmTZX90ZWLoZKUza4cVt8MexA==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" @@ -19438,9 +17291,8 @@ }, "node_modules/optimist": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", "dev": true, + "license": "MIT/X11", "dependencies": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" @@ -19448,15 +17300,13 @@ }, "node_modules/optimist/node_modules/minimist": { "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -19471,8 +17321,7 @@ }, "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==", + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -19493,8 +17342,7 @@ }, "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==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -19507,8 +17355,7 @@ }, "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==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19522,8 +17369,7 @@ }, "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==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -19533,21 +17379,18 @@ }, "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==" + "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==", + "license": "MIT", "engines": { "node": ">=8" } }, "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==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -19557,42 +17400,36 @@ }, "node_modules/ordered-ast-traverse": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ordered-ast-traverse/-/ordered-ast-traverse-1.1.1.tgz", - "integrity": "sha512-/VDCNFrMUftwD04zNwMMXUY5+5IN0tQKbElSC1v6f53ueZMuRKzZmR5HxTC5TQnwLVY1FH3KbulWc0DXZ5kBnQ==", "dev": true, + "license": "MIT", "dependencies": { "ordered-esprima-props": "~1.1.0" } }, "node_modules/ordered-esprima-props": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ordered-esprima-props/-/ordered-esprima-props-1.1.0.tgz", - "integrity": "sha512-RVQ/gx+EZY/txtizlzn4OY4Rto8vhM2HasczvmP1SJYBW6GD9vLfqx/7vgKEAFK2C9ynzz/evBArFyp3HAVmTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -19600,9 +17437,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -19615,9 +17451,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -19630,8 +17465,7 @@ }, "node_modules/p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -19644,9 +17478,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -19657,25 +17490,22 @@ }, "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": ">= 4" } }, "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==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pacote": { "version": "17.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", - "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", @@ -19705,24 +17535,20 @@ }, "node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "license": "(MIT AND Zlib)" }, "node_modules/param-case": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^2.2.0" } }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -19732,9 +17558,8 @@ }, "node_modules/parse-filepath": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, + "license": "MIT", "dependencies": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", @@ -19746,9 +17571,8 @@ }, "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": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -19764,39 +17588,34 @@ }, "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 + "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 + "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", "engines": { "node": ">= 0.10" } }, "node_modules/parse-passwd": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.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, + "license": "MIT", "dependencies": { "entities": "^4.4.0" }, @@ -19806,9 +17625,8 @@ }, "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": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -19820,9 +17638,8 @@ }, "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": { "parse5": "^7.0.0" }, @@ -19832,70 +17649,60 @@ }, "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/pascalcase": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-dirname": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true + "dev": true, + "license": "(WTFPL OR MIT)" }, "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==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "license": "MIT" }, "node_modules/path-root": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, + "license": "MIT", "dependencies": { "path-root-regex": "^0.1.0" }, @@ -19905,17 +17712,15 @@ }, "node_modules/path-root-regex": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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==", + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -19929,31 +17734,27 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "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 + "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", "engines": { "node": ">=8" } }, "node_modules/path2d-polyfill": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -19961,8 +17762,7 @@ }, "node_modules/pdfjs-dist": { "version": "3.11.174", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", - "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "license": "Apache-2.0", "engines": { "node": ">=18" }, @@ -19973,20 +17773,19 @@ }, "node_modules/performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "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==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", - "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -19994,41 +17793,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/pinkie": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pinkie-promise": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, + "license": "MIT", "dependencies": { "pinkie": "^2.0.0" }, @@ -20038,27 +17822,24 @@ }, "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", "engines": { "node": ">= 6" } }, "node_modules/piscina": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", - "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", "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": { "find-up": "^6.3.0" }, @@ -20071,9 +17852,8 @@ }, "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" @@ -20087,9 +17867,8 @@ }, "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", "dependencies": { "p-locate": "^6.0.0" }, @@ -20102,9 +17881,8 @@ }, "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": { "yocto-queue": "^1.0.0" }, @@ -20117,9 +17895,8 @@ }, "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" }, @@ -20132,18 +17909,16 @@ }, "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": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/pkg-dir/node_modules/yocto-queue": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -20153,9 +17928,8 @@ }, "node_modules/pkg-up": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^3.0.0" }, @@ -20165,9 +17939,8 @@ }, "node_modules/pkg-up/node_modules/find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^3.0.0" }, @@ -20177,9 +17950,8 @@ }, "node_modules/pkg-up/node_modules/locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -20190,9 +17962,8 @@ }, "node_modules/pkg-up/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -20205,9 +17976,8 @@ }, "node_modules/pkg-up/node_modules/p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.0.0" }, @@ -20217,17 +17987,23 @@ }, "node_modules/pkg-up/node_modules/path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/portscanner": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", - "integrity": "sha512-3MCx40XO6ChNJJHw1tTFukQK/M/8FacGZK/vGbnrKpozObrJzembYtfi7ZdA2hkF2Lojg77XhsKUPvF8eHKcDA==", "dev": true, "dependencies": { "async": "1.5.2" @@ -20237,28 +18013,30 @@ "npm": ">=1.0.0" } }, + "node_modules/positioning": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/positioning/-/positioning-2.0.1.tgz", + "integrity": "sha512-DsAgM42kV/ObuwlRpAzDTjH9E8fGKkMDJHWFX+kfNXSxh7UCCQxEmdjv/Ws5Ft1XDnt3JT8fIDYeKNSE2TbttA==", + "license": "MIT" + }, "node_modules/posix-character-classes": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/possible-typed-array-names": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -20274,6 +18052,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -20285,9 +18064,8 @@ }, "node_modules/postcss-import": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -20302,15 +18080,13 @@ }, "node_modules/postcss-import/node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/postcss-js": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, @@ -20327,8 +18103,6 @@ }, "node_modules/postcss-load-config": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, "funding": [ { @@ -20340,6 +18114,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" @@ -20362,9 +18137,8 @@ }, "node_modules/postcss-load-config/node_modules/lilconfig": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -20373,10 +18147,9 @@ } }, "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.3.tgz", - "integrity": "sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg==", + "version": "2.4.2", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -20386,9 +18159,8 @@ }, "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": { "cosmiconfig": "^9.0.0", "jiti": "^1.20.0", @@ -20415,61 +18187,15 @@ } } }, - "node_modules/postcss-loader/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/postcss-loader/node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/postcss-loader/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/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 + "dev": true, + "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" }, @@ -20479,9 +18205,8 @@ }, "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", @@ -20496,15 +18221,13 @@ }, "node_modules/postcss-modules-local-by-default/node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "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": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -20517,9 +18240,8 @@ }, "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==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -20532,9 +18254,8 @@ }, "node_modules/postcss-nested": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.11" }, @@ -20551,36 +18272,32 @@ }, "node_modules/postcss-scss": { "version": "0.1.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-0.1.9.tgz", - "integrity": "sha512-FkLd8Pxci394edesXqewjAd6eMnYGUPK5bgkYbYHX7YPeJDcuaKMuHnXsd0i3tnXJOLTuX+L+m3edda1IKMrbQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss": "^5.1.0" } }, "node_modules/postcss-scss/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/postcss-scss/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/postcss-scss/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -20594,27 +18311,24 @@ }, "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/postcss-scss/node_modules/has-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/postcss-scss/node_modules/postcss": { "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^1.1.3", "js-base64": "^2.1.9", @@ -20627,18 +18341,16 @@ }, "node_modules/postcss-scss/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/postcss-scss/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -20648,9 +18360,8 @@ }, "node_modules/postcss-scss/node_modules/supports-color": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^1.0.0" }, @@ -20659,10 +18370,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", - "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "version": "6.0.16", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -20673,23 +18383,19 @@ }, "node_modules/postcss-value-parser": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/preprocess": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/preprocess/-/preprocess-3.2.0.tgz", - "integrity": "sha512-cO+Rf+Ose/eD+ze8Hxd9p9nS1xT8thYqv8owG/V8+IS/Remd7Z17SvaRK/oJxp08yaM8zb+QTckDKJUul2pk7g==", "dev": true, "dependencies": { "xregexp": "3.1.0" @@ -20699,10 +18405,9 @@ } }, "node_modules/prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", - "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "version": "3.2.5", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -20715,9 +18420,8 @@ }, "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" }, @@ -20727,9 +18431,8 @@ }, "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", @@ -20741,9 +18444,8 @@ }, "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" }, @@ -20753,23 +18455,19 @@ }, "node_modules/proc-log": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "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==", - "dev": true + "license": "MIT" }, "node_modules/promise": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "asap": "~2.0.3" @@ -20777,13 +18475,11 @@ }, "node_modules/promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + "license": "ISC" }, "node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -20794,10 +18490,8 @@ }, "node_modules/protractor": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, + "license": "MIT", "dependencies": { "@types/q": "^0.0.32", "@types/selenium-webdriver": "^3.0.0", @@ -20825,27 +18519,24 @@ }, "node_modules/protractor/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -20859,9 +18550,8 @@ }, "node_modules/protractor/node_modules/cliui": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -20870,18 +18560,16 @@ }, "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -20891,9 +18579,8 @@ }, "node_modules/protractor/node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -20904,9 +18591,8 @@ }, "node_modules/protractor/node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -20916,9 +18602,8 @@ }, "node_modules/protractor/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -20931,9 +18616,8 @@ }, "node_modules/protractor/node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -20943,9 +18627,8 @@ }, "node_modules/protractor/node_modules/q": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" @@ -20953,27 +18636,24 @@ }, "node_modules/protractor/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/source-map-support": { "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "^0.5.6" } }, "node_modules/protractor/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -20983,24 +18663,21 @@ }, "node_modules/protractor/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/protractor/node_modules/y18n": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/protractor/node_modules/yargs": { "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -21020,9 +18697,8 @@ }, "node_modules/protractor/node_modules/yargs-parser": { "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -21033,9 +18709,8 @@ }, "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" @@ -21046,37 +18721,32 @@ }, "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 + "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 + "dev": true, + "license": "MIT" }, "node_modules/pug": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", - "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pug-code-gen": "^2.0.2", @@ -21091,9 +18761,8 @@ }, "node_modules/pug-attrs": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", - "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "constantinople": "^3.0.1", @@ -21103,9 +18772,8 @@ }, "node_modules/pug-code-gen": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.3.tgz", - "integrity": "sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "constantinople": "^3.1.2", @@ -21120,16 +18788,14 @@ }, "node_modules/pug-error": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", - "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/pug-filters": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", - "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "clean-css": "^4.1.11", @@ -21143,9 +18809,8 @@ }, "node_modules/pug-filters/node_modules/camelcase": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -21153,9 +18818,8 @@ }, "node_modules/pug-filters/node_modules/cliui": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", "dev": true, + "license": "ISC", "optional": true, "dependencies": { "center-align": "^0.1.1", @@ -21165,9 +18829,8 @@ }, "node_modules/pug-filters/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -21175,9 +18838,8 @@ }, "node_modules/pug-filters/node_modules/uglify-js": { "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "dependencies": { "source-map": "~0.5.1", @@ -21195,9 +18857,8 @@ }, "node_modules/pug-filters/node_modules/wordwrap": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", "dev": true, + "license": "MIT/X11", "optional": true, "engines": { "node": ">=0.4.0" @@ -21205,9 +18866,8 @@ }, "node_modules/pug-filters/node_modules/yargs": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "camelcase": "^1.0.2", @@ -21218,9 +18878,8 @@ }, "node_modules/pug-lexer": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", - "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "character-parser": "^2.1.1", @@ -21230,9 +18889,8 @@ }, "node_modules/pug-linker": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", - "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^1.3.3", @@ -21241,9 +18899,8 @@ }, "node_modules/pug-load": { "version": "2.0.12", - "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", - "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "object-assign": "^4.1.0", @@ -21252,9 +18909,8 @@ }, "node_modules/pug-parser": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", - "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^1.3.3", @@ -21263,16 +18919,14 @@ }, "node_modules/pug-runtime": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", - "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/pug-strip-comments": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", - "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pug-error": "^1.3.3" @@ -21280,24 +18934,21 @@ }, "node_modules/pug-walk": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", - "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/q": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" @@ -21305,18 +18956,137 @@ }, "node_modules/qjobs": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.9" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "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" }, @@ -21329,8 +19099,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -21345,40 +19113,29 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -21391,9 +19148,8 @@ }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -21403,33 +19159,28 @@ }, "node_modules/react-is": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/read-cache": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.3.0" } }, "node_modules/read-cache/node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/read-package-json": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.1.tgz", - "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "license": "ISC", "dependencies": { "glob": "^10.2.2", "json-parse-even-better-errors": "^3.0.0", @@ -21442,8 +19193,7 @@ }, "node_modules/read-package-json-fast": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -21453,227 +19203,77 @@ } }, "node_modules/read-package-json/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.3.15", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/read-package-json/node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/normalize-package-data": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", - "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/read-pkg-up/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, + "node_modules/read-package-json/node_modules/hosted-git-info": { + "version": "7.0.2", + "license": "ISC", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "lru-cache": "^10.0.1" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/read-pkg-up/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, + "node_modules/read-package-json/node_modules/lru-cache": { + "version": "10.2.2", + "license": "ISC", "engines": { - "node": ">=8" + "node": "14 || >=16.14" } }, - "node_modules/read-pkg-up/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "6.0.1", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/read-pkg": { + "version": "3.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg/node_modules/hosted-git-info": { "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/read-pkg/node_modules/normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -21683,9 +19283,8 @@ }, "node_modules/read-pkg/node_modules/path-type": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^3.0.0" }, @@ -21695,17 +19294,15 @@ }, "node_modules/read-pkg/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -21717,9 +19314,8 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "devOptional": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -21729,9 +19325,8 @@ }, "node_modules/readdirp/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -21741,9 +19336,8 @@ }, "node_modules/rechoir": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, + "license": "MIT", "dependencies": { "resolve": "^1.9.0" }, @@ -21751,36 +19345,20 @@ "node": ">= 0.10" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reflect-metadata": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -21790,24 +19368,21 @@ }, "node_modules/regenerator-runtime": { "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regex-not": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, + "license": "MIT", "dependencies": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" @@ -21818,9 +19393,8 @@ }, "node_modules/regex-not/node_modules/extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "license": "MIT", "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -21831,9 +19405,8 @@ }, "node_modules/regex-not/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -21843,15 +19416,13 @@ }, "node_modules/regex-parser": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", - "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "define-properties": "^1.2.1", @@ -21867,9 +19438,8 @@ }, "node_modules/regexpu-core": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -21884,9 +19454,8 @@ }, "node_modules/regjsparser": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" }, @@ -21896,8 +19465,6 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -21905,43 +19472,37 @@ }, "node_modules/relateurl": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/remove-trailing-separator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/repeat-element": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/repeat-string": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/request": { "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -21970,9 +19531,8 @@ }, "node_modules/request/node_modules/form-data": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -21984,44 +19544,38 @@ }, "node_modules/request/node_modules/qs": { "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.6" } }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/require-main-filename": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "license": "ISC" }, "node_modules/requires-port": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve": { "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -22036,9 +19590,8 @@ }, "node_modules/resolve-dir": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, + "license": "MIT", "dependencies": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" @@ -22049,30 +19602,16 @@ }, "node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", "dev": true, - "dependencies": { - "global-dirs": "^0.1.1" - }, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve-pkg": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", - "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -22082,16 +19621,13 @@ }, "node_modules/resolve-url": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve-url-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, + "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", @@ -22105,9 +19641,8 @@ }, "node_modules/resolve-url-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -22119,17 +19654,15 @@ }, "node_modules/resolve-url-loader/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "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==", + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -22140,26 +19673,23 @@ }, "node_modules/ret": { "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12" } }, "node_modules/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -22167,15 +19697,13 @@ }, "node_modules/rfdc": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/right-align": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "align-text": "^0.1.1" @@ -22186,10 +19714,8 @@ }, "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", "devOptional": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -22201,12 +19727,13 @@ } }, "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.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -22216,37 +19743,43 @@ "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.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", "fsevents": "~2.3.2" } }, "node_modules/run-async": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -22262,34 +19795,28 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/rx": { "version": "2.3.24", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz", - "integrity": "sha512-Ue4ZB7Dzbn2I9sIj8ws536nOP2S53uypyCkCz9q0vlYD5Kn6/pu4dE+wt2ZfFzd9m73hiYKnnCb1OyKqc+MRkg==", "dev": true }, "node_modules/rxjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", - "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "dependencies": { - "tslib": "~2.1.0" + "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" - }, "node_modules/safe-array-concat": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -22305,30 +19832,24 @@ }, "node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "license": "MIT" }, "node_modules/safe-json-parse": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "node_modules/safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, + "license": "MIT", "dependencies": { "ret": "~0.1.10" } }, "node_modules/safe-regex-test": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -22343,19 +19864,16 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "license": "MIT" }, "node_modules/safevalues": { "version": "0.3.4", - "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", - "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" + "license": "Apache-2.0" }, "node_modules/sass": { - "version": "1.77.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", - "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", + "version": "1.77.1", "dev": true, + "license": "MIT", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -22370,9 +19888,8 @@ }, "node_modules/sass-loader": { "version": "14.1.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", - "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", "dev": true, + "license": "MIT", "dependencies": { "neo-async": "^2.6.2" }, @@ -22410,8 +19927,6 @@ }, "node_modules/saucelabs": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, "dependencies": { "https-proxy-agent": "^2.2.1" @@ -22422,9 +19937,8 @@ }, "node_modules/saucelabs/node_modules/agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "license": "MIT", "dependencies": { "es6-promisify": "^5.0.0" }, @@ -22434,18 +19948,16 @@ }, "node_modules/saucelabs/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/saucelabs/node_modules/https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -22455,16 +19967,14 @@ } }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true + "version": "1.3.0", + "dev": true, + "license": "ISC" }, "node_modules/schema-utils": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -22481,15 +19991,13 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jszip": "^3.1.3", "rimraf": "^2.5.4", @@ -22502,10 +20010,8 @@ }, "node_modules/selenium-webdriver/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -22515,9 +20021,8 @@ }, "node_modules/selenium-webdriver/node_modules/tmp": { "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -22527,9 +20032,8 @@ }, "node_modules/selfsigned": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -22540,8 +20044,7 @@ }, "node_modules/semver": { "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -22554,8 +20057,7 @@ }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -22565,14 +20067,12 @@ }, "node_modules/semver/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/send": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -22594,24 +20094,21 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -22621,15 +20118,13 @@ }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/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, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -22639,27 +20134,24 @@ }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/serialize-javascript": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/serve-index": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -22675,27 +20167,24 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -22708,27 +20197,23 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-static": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -22741,13 +20226,11 @@ }, "node_modules/set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -22762,9 +20245,8 @@ }, "node_modules/set-function-name": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -22777,9 +20259,8 @@ }, "node_modules/set-value": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, + "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -22792,21 +20273,17 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -22816,8 +20293,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -22827,26 +20303,23 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/shell-quote": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shelljs": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha512-Ny0KN4dyT8ZSCE0frtcbAJGoM/HTArpyPkeli1/00aYfm0sbD/Gk/4x7N2DP9QKGpBsiQH7n6rpm1L79RtviEQ==", "dev": true, + "license": "BSD*", "bin": { "shjs": "bin/shjs" }, @@ -22856,8 +20329,7 @@ }, "node_modules/showdown": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/showdown/-/showdown-1.9.1.tgz", - "integrity": "sha512-9cGuS382HcvExtf5AHk7Cb4pAeQQ+h0eTr33V1mu+crYWV4KvWAw6el92bDrqGEk5d46Ai/fhbEUwqJ/mTCNEA==", + "license": "BSD-3-Clause", "dependencies": { "yargs": "^14.2" }, @@ -22867,16 +20339,14 @@ }, "node_modules/showdown/node_modules/ansi-regex": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/showdown/node_modules/cliui": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "license": "ISC", "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -22885,13 +20355,11 @@ }, "node_modules/showdown/node_modules/emoji-regex": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "license": "MIT" }, "node_modules/showdown/node_modules/find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", "dependencies": { "locate-path": "^3.0.0" }, @@ -22901,16 +20369,14 @@ }, "node_modules/showdown/node_modules/is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/showdown/node_modules/locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -22921,8 +20387,7 @@ }, "node_modules/showdown/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -22935,8 +20400,7 @@ }, "node_modules/showdown/node_modules/p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", "dependencies": { "p-limit": "^2.0.0" }, @@ -22946,16 +20410,14 @@ }, "node_modules/showdown/node_modules/path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/showdown/node_modules/string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "license": "MIT", "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -22967,8 +20429,7 @@ }, "node_modules/showdown/node_modules/strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", "dependencies": { "ansi-regex": "^4.1.0" }, @@ -22978,8 +20439,7 @@ }, "node_modules/showdown/node_modules/wrap-ansi": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -22991,13 +20451,11 @@ }, "node_modules/showdown/node_modules/y18n": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + "license": "ISC" }, "node_modules/showdown/node_modules/yargs": { "version": "14.2.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", - "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "license": "MIT", "dependencies": { "cliui": "^5.0.0", "decamelize": "^1.2.0", @@ -23014,8 +20472,7 @@ }, "node_modules/showdown/node_modules/yargs-parser": { "version": "15.0.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", - "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -23023,9 +20480,8 @@ }, "node_modules/side-channel": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -23039,27 +20495,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==" - }, "node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "license": "ISC" }, "node_modules/sigstore": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", - "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "version": "2.3.0", + "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.3.2", + "@sigstore/bundle": "^2.3.1", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "@sigstore/sign": "^2.3.2", - "@sigstore/tuf": "^2.3.4", - "@sigstore/verify": "^1.2.1" + "@sigstore/protobuf-specs": "^0.3.1", + "@sigstore/sign": "^2.3.0", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -23083,18 +20532,19 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true }, "node_modules/simple-fmt": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz", - "integrity": "sha512-9a3zTDDh9LXbTR37qBhACWIQ/mP/ry5xtmbE98BJM8GR02sanCkfMzp7AdCTqYhkBZggK/w7hJtc8Pb9nmo16A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", "optional": true, "dependencies": { "decompress-response": "^4.2.0", @@ -23104,23 +20554,20 @@ }, "node_modules/simple-is": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz", - "integrity": "sha512-GJXhv3r5vdj5tGWO+rcrWgjU2azLB+fb7Ehh3SmZpXE0o4KrrFLti0w4mdDCbR29X/z0Ls20ApjZitlpAXhAeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -23128,9 +20575,8 @@ }, "node_modules/snapdragon": { "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, + "license": "MIT", "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", @@ -23147,9 +20593,8 @@ }, "node_modules/snapdragon-node": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, + "license": "MIT", "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -23161,9 +20606,8 @@ }, "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.0" }, @@ -23173,9 +20617,8 @@ }, "node_modules/snapdragon-node/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -23186,9 +20629,8 @@ }, "node_modules/snapdragon-util": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^3.2.0" }, @@ -23198,9 +20640,8 @@ }, "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -23210,33 +20651,29 @@ }, "node_modules/snapdragon/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/snapdragon/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/socket.io": { "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -23252,9 +20689,8 @@ }, "node_modules/socket.io-adapter": { "version": "2.5.4", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", - "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "~4.3.4", "ws": "~8.11.0" @@ -23262,9 +20698,8 @@ }, "node_modules/socket.io-parser": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -23275,9 +20710,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -23286,9 +20720,8 @@ }, "node_modules/sockjs/node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -23298,17 +20731,15 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/socks": { "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -23320,8 +20751,7 @@ }, "node_modules/socks-proxy-agent": { "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -23333,26 +20763,23 @@ }, "node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/source-map-js": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", - "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", "dev": true, + "license": "MIT", "dependencies": { "iconv-lite": "^0.6.3", "source-map-js": "^1.0.2" @@ -23370,10 +20797,8 @@ }, "node_modules/source-map-resolve": { "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, + "license": "MIT", "dependencies": { "atob": "^2.1.2", "decode-uri-component": "^0.2.0", @@ -23384,9 +20809,8 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -23394,30 +20818,25 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-url": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/spawn-command": { "version": "0.0.2-1", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -23425,28 +20844,24 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "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.17", + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -23460,9 +20875,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -23474,9 +20888,8 @@ }, "node_modules/split-string": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, + "license": "MIT", "dependencies": { "extend-shallow": "^3.0.0" }, @@ -23486,9 +20899,8 @@ }, "node_modules/split-string/node_modules/extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "license": "MIT", "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -23499,9 +20911,8 @@ }, "node_modules/split-string/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -23509,26 +20920,15 @@ "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, "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 + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -23551,14 +20951,12 @@ }, "node_modules/sshpk/node_modules/jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ssri": { "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -23568,16 +20966,13 @@ }, "node_modules/stable": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/static-extend": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, + "license": "MIT", "dependencies": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -23588,18 +20983,16 @@ }, "node_modules/statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/streamroller": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, + "license": "MIT", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -23611,9 +21004,8 @@ }, "node_modules/streamroller/node_modules/fs-extra": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -23625,34 +21017,29 @@ }, "node_modules/streamroller/node_modules/jsonfile": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, + "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/streamroller/node_modules/universalify": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -23666,18 +21053,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/string-template": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -23690,8 +21075,7 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -23701,29 +21085,10 @@ "node": ">=8" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.trim": { "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -23739,9 +21104,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -23753,9 +21117,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -23770,20 +21133,17 @@ }, "node_modules/stringmap": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz", - "integrity": "sha512-mR1LEHDw6TsHa+LwJeeBc9ZqZqEOm7bHidgxMmDg8HB/rbA1HhDeT08gS67CCCG/xrgIfQx5tW42pd8vFpLUow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stringset": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz", - "integrity": "sha512-km3jeiRpmySChl1oLiBE2ESdG5k/4+6tjENVL6BB3mdmKBiUikI5ks4paad2WAKsxzpNiBqBBbXCC12QqlpLWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -23794,8 +21154,7 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -23805,39 +21164,24 @@ }, "node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -23847,9 +21191,8 @@ }, "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", @@ -23864,9 +21207,8 @@ }, "node_modules/sucrase": { "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -23886,24 +21228,22 @@ }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.3.15", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -23917,30 +21257,13 @@ }, "node_modules/sucrase/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 - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "MIT" }, "node_modules/supports-color": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -23950,8 +21273,7 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -23961,17 +21283,15 @@ }, "node_modules/symbol-observable": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/synckit": { "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", "dev": true, + "license": "MIT", "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" @@ -23985,9 +21305,8 @@ }, "node_modules/tailwindcss": { "version": "3.3.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.7.tgz", - "integrity": "sha512-pjgQxDZPvyS/nG3ZYkyCvsbONJl7GdOejfm24iMt2ElYQQw8Jc4p0m8RdMp7mznPD0kUhfzwV3zAwa80qI0zmQ==", "dev": true, + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -24022,9 +21341,8 @@ }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -24034,17 +21352,15 @@ }, "node_modules/tapable": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tar": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -24059,9 +21375,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -24075,8 +21390,7 @@ }, "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==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -24086,8 +21400,7 @@ }, "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -24097,16 +21410,14 @@ }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { "node": ">=8" } }, "node_modules/tar/node_modules/mkdirp": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -24116,14 +21427,12 @@ }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/terser": { "version": "5.29.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", - "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -24139,9 +21448,8 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -24173,9 +21481,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -24189,24 +21496,21 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -24222,15 +21526,13 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -24242,9 +21544,8 @@ }, "node_modules/test-exclude/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" @@ -24252,9 +21553,8 @@ }, "node_modules/test-exclude/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" }, @@ -24262,35 +21562,32 @@ "node": "*" } }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "engines": { - "node": ">=0.10" + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" } }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } }, "node_modules/thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -24300,30 +21597,18 @@ }, "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 - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, - "dependencies": { - "readable-stream": "3" - } + "license": "MIT" }, "node_modules/thunky": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tiny-lr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", - "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, + "license": "MIT", "dependencies": { "body": "^5.1.0", "debug": "^3.1.0", @@ -24335,36 +21620,42 @@ }, "node_modules/tiny-lr/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, + "node_modules/tinyexec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tmp": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.14" } }, "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/to-object-path": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^3.0.2" }, @@ -24374,9 +21665,8 @@ }, "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, + "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" }, @@ -24386,9 +21676,8 @@ }, "node_modules/to-regex": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, + "license": "MIT", "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -24401,9 +21690,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -24413,9 +21701,8 @@ }, "node_modules/to-regex/node_modules/define-property": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, + "license": "MIT", "dependencies": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -24426,9 +21713,8 @@ }, "node_modules/to-regex/node_modules/extend-shallow": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, + "license": "MIT", "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -24439,9 +21725,8 @@ }, "node_modules/to-regex/node_modules/is-descriptor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, + "license": "MIT", "dependencies": { "is-accessor-descriptor": "^1.0.1", "is-data-descriptor": "^1.0.1" @@ -24452,9 +21737,8 @@ }, "node_modules/to-regex/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4" }, @@ -24464,25 +21748,22 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/token-stream": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", - "integrity": "sha512-nfjOAu/zAWmX9tgwi5NRp7O7zTDUD1miHiB40klUnAh9qnL1iXdgzcz/i5dMaL5jahcBAaSfmNOBBJBLJW8TEg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/tough-cookie": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -24495,37 +21776,26 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", "optional": true }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/tryor": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz", - "integrity": "sha512-2+ilNA00DGvbUYYbRrm3ux+snbo7I6uPXMw8I4p/QMl7HUOWBBZFbk+Mpr8/IAPDQE+LQ8vOdlI6xEzjc+e/BQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ts-api-utils": { "version": "1.3.0", - "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" }, @@ -24535,23 +21805,20 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/ts-md5": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", - "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==", + "license": "MIT", "engines": { "node": ">=12" } }, "node_modules/ts-node": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -24592,24 +21859,21 @@ }, "node_modules/ts-node/node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/tsconfig-paths": { "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -24619,9 +21883,8 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -24631,13 +21894,11 @@ }, "node_modules/tslib": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "license": "0BSD" }, "node_modules/tuf-js": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", - "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "license": "MIT", "dependencies": { "@tufjs/models": "2.0.1", "debug": "^4.3.4", @@ -24649,9 +21910,8 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -24661,15 +21921,13 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -24679,8 +21937,7 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -24690,9 +21947,8 @@ }, "node_modules/type-is": { "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -24703,9 +21959,8 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -24717,9 +21972,8 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -24736,9 +21990,8 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -24756,9 +22009,8 @@ }, "node_modules/typed-array-length": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -24776,15 +22028,13 @@ }, "node_modules/typed-assert": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/typescript": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24794,9 +22044,7 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.38", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", - "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", + "version": "0.7.37", "dev": true, "funding": [ { @@ -24812,15 +22060,15 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "engines": { "node": "*" } }, "node_modules/uglify-js": { "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "commander": "~2.19.0", "source-map": "~0.6.1" @@ -24834,29 +22082,27 @@ }, "node_modules/uglify-js/node_modules/commander": { "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/uglify-js/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/uglify-to-browserify": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==" + "dev": true, + "license": "MIT", + "optional": true }, "node_modules/unbox-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -24869,56 +22115,48 @@ }, "node_modules/unc-path-regex": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/underscore": { "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/underscore.string": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", "engines": { "node": "*" } }, "node_modules/undici": { "version": "6.11.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.11.1.tgz", - "integrity": "sha512-KyhzaLJnV1qa3BSHdj4AZ2ndqI0QWPxYzaIOio0WzcEJB9gvuysprJSLtpvc2D9mhR9jPDUk7xlJlZbH2KR5iw==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.0" } }, "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 + "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" @@ -24929,27 +22167,24 @@ }, "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/union-value": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, + "license": "MIT", "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -24962,8 +22197,7 @@ }, "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==", + "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -24973,8 +22207,7 @@ }, "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==", + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -24984,27 +22217,24 @@ }, "node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.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/unset-value": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, + "license": "MIT", "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -25015,9 +22245,8 @@ }, "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "dev": true, + "license": "MIT", "dependencies": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -25029,9 +22258,8 @@ }, "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dev": true, + "license": "MIT", "dependencies": { "isarray": "1.0.0" }, @@ -25041,33 +22269,28 @@ }, "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/unset-value/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/upath": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4", "yarn": "*" } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.0.15", "dev": true, "funding": [ { @@ -25083,9 +22306,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "picocolors": "^1.0.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -25096,78 +22320,75 @@ }, "node_modules/upper-case": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", - "dev": true + "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==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/uri-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", - "integrity": "sha512-8pMuAn4KacYdGMkFaoQARicp4HSw24/DHOVKWqVRJ8LhhAwPPFpdGvdL9184JVmUwe7vz7Z9n6IqI6t5n2ELdg==", "dev": true, + "license": "WTFPL OR MIT", "engines": { "node": ">= 0.10" } }, "node_modules/urix": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/use": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.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/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, + "license": "MIT", "bin": { "uuid": "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 + "dev": true, + "license": "MIT" }, "node_modules/v8flags": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, + "license": "MIT", "dependencies": { "homedir-polyfill": "^1.0.1" }, @@ -25177,8 +22398,7 @@ }, "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==", + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -25186,29 +22406,26 @@ }, "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==", + "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/verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -25217,9 +22434,8 @@ }, "node_modules/vite": { "version": "5.1.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.7.tgz", - "integrity": "sha512-sgnEEFTZYMui/sTlH1/XEnVNHMujOahPLGMxn1+5sIT45Xjng1Ec1K78jRP15dSmVgg5WBin9yO81j3o9OxofA==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.19.3", "postcss": "^8.4.35", @@ -25640,10 +22856,9 @@ }, "node_modules/vite/node_modules/esbuild": { "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -25678,18 +22893,16 @@ }, "node_modules/void-elements": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -25700,26 +22913,23 @@ }, "node_modules/wbuf": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webdriver-js-extender": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/selenium-webdriver": "^3.0.0", "selenium-webdriver": "^3.0.1" @@ -25730,9 +22940,8 @@ }, "node_modules/webdriver-manager": { "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", "dev": true, + "license": "MIT", "dependencies": { "adm-zip": "^0.5.2", "chalk": "^1.1.1", @@ -25755,27 +22964,24 @@ }, "node_modules/webdriver-manager/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/webdriver-manager/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/webdriver-manager/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -25789,16 +22995,13 @@ }, "node_modules/webdriver-manager/node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/webdriver-manager/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -25808,18 +23011,16 @@ }, "node_modules/webdriver-manager/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/webdriver-manager/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -25829,9 +23030,8 @@ }, "node_modules/webdriver-manager/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -25840,13 +23040,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", "optional": true }, "node_modules/webpack": { "version": "5.90.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", - "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -25891,9 +23091,8 @@ }, "node_modules/webpack-dev-middleware": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", - "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.12", @@ -25919,9 +23118,8 @@ }, "node_modules/webpack-dev-server": { "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -25978,9 +23176,8 @@ }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -26001,9 +23198,8 @@ }, "node_modules/webpack-dev-server/node_modules/ws": { "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -26022,9 +23218,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -26036,18 +23231,16 @@ }, "node_modules/webpack-sources": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, "node_modules/webpack-subresource-integrity": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, + "license": "MIT", "dependencies": { "typed-assert": "^1.0.8" }, @@ -26066,9 +23259,8 @@ }, "node_modules/webpack/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -26082,18 +23274,16 @@ }, "node_modules/webpack/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -26104,30 +23294,26 @@ }, "node_modules/webpack/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/webpack/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 + "dev": true, + "license": "MIT" }, "node_modules/webpack/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/webpack/node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -26143,9 +23329,8 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -26157,9 +23342,8 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -26168,6 +23352,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "optional": true, "dependencies": { "tr46": "~0.0.3", @@ -26176,8 +23361,7 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -26190,9 +23374,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -26206,14 +23389,12 @@ }, "node_modules/which-module": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + "license": "ISC" }, "node_modules/which-typed-array": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -26232,6 +23413,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -26239,23 +23421,21 @@ }, "node_modules/wildcard": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/window-size": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "dev": true, + "optional": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/with": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", - "integrity": "sha512-uAnSsFGfSpF6DNhBXStvlZILfHJfJu4eUkfbRGk94kGO1Ta7bg6FwfvoOhhyHAJuFbCw+0xk4uJ3u57jLvlCJg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "acorn": "^3.1.0", @@ -26264,9 +23444,8 @@ }, "node_modules/with/node_modules/acorn": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw==", "dev": true, + "license": "MIT", "optional": true, "bin": { "acorn": "bin/acorn" @@ -26277,26 +23456,23 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wordwrap": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -26309,8 +23485,7 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -26325,8 +23500,7 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -26339,8 +23513,7 @@ }, "node_modules/wrap-ansi-cjs/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -26350,13 +23523,11 @@ }, "node_modules/wrap-ansi-cjs/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -26369,8 +23540,7 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -26380,20 +23550,17 @@ }, "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "devOptional": true + "devOptional": true, + "license": "ISC" }, "node_modules/ws": { "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -26412,9 +23579,8 @@ }, "node_modules/xml2js": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, + "license": "MIT", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -26425,46 +23591,32 @@ }, "node_modules/xmlbuilder": { "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } }, "node_modules/xregexp": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.0.tgz", - "integrity": "sha512-4Y1x6DyB8xRoxosooa6PlGWqmmSKatbzhrftZ7Purmm4B8R4qIEJG1A2hZsdz5DhmIqS0msC0I7KEq93GphEVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, - "engines": { - "node": ">= 6" - } + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -26480,26 +23632,23 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -26507,15 +23656,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zlib-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/zlib-browserify/-/zlib-browserify-0.0.1.tgz", - "integrity": "sha512-fheIDCKXU0YAGZMv4FFwVTBMQRSv2ZjNqRN1VkZjetZDK/BC/hViEhasTh0kTeogcsIAl5gYE04GN53trT+cFw==" - }, "node_modules/zone.js": { - "version": "0.14.6", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.6.tgz", - "integrity": "sha512-vyRNFqofdaHVdWAy7v3Bzmn84a1JHWSjpuTZROT/uYn8I3p2cmo7Ro9twFmYRQDPhiYOV7QLk0hhY4JJQVqS6Q==" + "version": "0.14.5", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + } } } } diff --git a/package.json b/package.json index b3fbe7a25c..6a353dbcaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.9", + "version": "10.0.1-22", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", @@ -14,8 +14,10 @@ "build:angular17": "ng build", "lint:fix": "ng lint --fix", "lint": "ng lint", - "serve:angular17": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --configuration $NODE_ENV", + "serve:angular17": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --poll=2000 --configuration $NODE_ENV --proxy-config proxy.conf.json", + "serve:angular17-compose": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --configuration $NODE_ENV --proxy-config proxy-compose.conf.json", "start": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular17", + "start-compose": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular17-compose", "watch:angular1": "grunt delta", "deploy:build2api": "ng build --delete-output-path=true --optimization=true --configuration production --output-path dist", "deploy": "run-s -l build:angular1 deploy:build2api", @@ -33,28 +35,28 @@ "@angular/compiler": "^17.3.6", "@angular/core": "^17.3.6", "@angular/forms": "^17.3.6", - "@angular/material": "^17.3.6", - "@angular/material-moment-adapter": "^17.3.6", + "@angular/material": "^17.3.10", + "@angular/material-date-fns-adapter": "^17.3.10", "@angular/platform-browser": "^17.3.6", "@angular/platform-browser-dynamic": "^17.3.6", "@angular/router": "^17.3.6", "@angular/service-worker": "^17.3.6", "@angular/upgrade": "^17.3.6", - "@ctrl/ngx-emoji-mart": "^9.2.0", + "@ctrl/ngx-emoji-mart": "^9.3.0", "@ngneat/hotkeys": "^4.0.0", + "@ngstack/code-editor": "7.3.0", "@uirouter/angular": "^13.0", "@uirouter/angular-hybrid": "^17.1.0", "@uirouter/angularjs": "^1.0.30", "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", + "@worktile/gantt": "^18.0.5", "angular": "1.5.11", - "angular-cookies": "1.5.11", - "angular-file-upload": "~1", + "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", - "angular-local-storage": "0.7.1", "angular-markdown-filter": "1.3.2", "angular-md5": "0.1.10", - "angular-mocks": "1.5.11", + "angular-mocks": "1.8.3", "angular-nvd3": "1.0.9", "angular-resource": "1.5.11", "angular-sanitize": "1.5.11", @@ -69,23 +71,30 @@ "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", + "date-fns": "^3.6.0", "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", + "html2canvas": "^1.4.1", + "html5-qrcode": "^2.3.8", "jquery": "2.1.4", + "jszip": "^3.10.1", "lodash": "~4.17", - "lottie-web": "^5.12.2", + "lottie-web": "^5.13.0", "marked": "^11.1.0", "moment": "^2.29.4", + "monaco-editor": "^0.44.0", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", - "ng-flex-layout": "^17.3.4-beta.1", - "ng2-pdf-viewer": "^10.0", + "ng-flex-layout": "^17.3.7-beta.1", + "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.39", + "ngx-entity-service": "^0.0.41", "ngx-lottie": "^11.0.2", + "ngx-monaco-editor-v2": "^17.0.1", "nvd3": "1.8.6", - "rxjs": "~7.4.0", + "qrcode": "^1.5.4", + "rxjs": "~7.8.2", "ts-md5": "^1.3.1", "tslib": "^2.6.2", "underscore.string": "2.3.3", @@ -100,13 +109,13 @@ "@angular-eslint/template-parser": "^17.3.0", "@angular/compiler-cli": "^17.3.6", "@angular/language-service": "^17.3.6", - "@commitlint/cli": "^16.0.1", - "@commitlint/config-conventional": "^17", + "@commitlint/cli": "^20.5.0", + "@commitlint/config-conventional": "^20", "@types/angular": "1.5.11", "@types/canvas-confetti": "^1.6.0", "@types/d3": "^3.5.17", "@types/file-saver": "^2.0.1", - "@types/jasmine": "~3.9.1", + "@types/jasmine": "~6.0.0", "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", @@ -150,7 +159,7 @@ "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "load-grunt-tasks": "^5.0.0", - "npm-run-all": "^4.1.5", + "npm-run-all2": "^7.0", "postcss": "^8.4.27", "postcss-scss": "^0.1.7", "prettier": "^3.1.0", @@ -164,7 +173,10 @@ "optionalDependencies": { "@nx/nx-darwin-arm64": "^18.0", "@nx/nx-darwin-x64": "^18.0", + "@nx/nx-linux-arm64-gnu": "^18.0", "@nx/nx-linux-x64-gnu": "^18.0", - "@nx/nx-win32-x64-msvc": "^18.0" + "@nx/nx-win32-x64-msvc": "^18.0", + "@rollup/rollup-linux-arm64-gnu": "*", + "@rollup/rollup-linux-x64-gnu": "*" } } diff --git a/proxy-compose.conf.json b/proxy-compose.conf.json new file mode 100644 index 0000000000..4b62591235 --- /dev/null +++ b/proxy-compose.conf.json @@ -0,0 +1,6 @@ +{ + "/api": { + "target": "http://doubtfire-api:3000", + "secure": false + } +} diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 0000000000..f6ccc83cc6 --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,10 @@ +{ + "/api": { + "target": "http://localhost:3000", + "secure": false + }, + "/lti/api": { + "target": "http://host.docker.internal:3001", + "secure": false + } +} diff --git a/src/app/account/edit-profile/edit-profile.component.html b/src/app/account/edit-profile/edit-profile.component.html index 54a4e0e362..a7b9c7b6e9 100644 --- a/src/app/account/edit-profile/edit-profile.component.html +++ b/src/app/account/edit-profile/edit-profile.component.html @@ -1,7 +1,9 @@
- + @if (!loading) { + + }
diff --git a/src/app/account/edit-profile/edit-profile.component.ts b/src/app/account/edit-profile/edit-profile.component.ts index 266530b422..55c6143ca4 100644 --- a/src/app/account/edit-profile/edit-profile.component.ts +++ b/src/app/account/edit-profile/edit-profile.component.ts @@ -1,9 +1,27 @@ -import { Component } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; +import {StateService} from '@uirouter/core'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; @Component({ selector: 'f-edit-profile', templateUrl: './edit-profile.component.html', styleUrls: ['./edit-profile.component.scss'], }) -export class EditProfileComponent { +export class EditProfileComponent implements OnInit { + public loading: boolean = true; + + constructor( + private authenticationService: AuthenticationService, + private state: StateService, + ) {} + + public ngOnInit(): void { + this.loading = true; + this.authenticationService.afterAuthCall((result) => { + if (!result) { + return this.state.go('sign_in'); + } + this.loading = false; + }); + } } diff --git a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html index 9b294d5597..9c91b329f7 100644 --- a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html +++ b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html @@ -15,27 +15,10 @@

Activities

{{ activityType.name }} } @else { - -
- - - - - -
- - } - - + } @@ -52,12 +35,11 @@

Activities

{{ activityType.abbreviation }}
- } @else { #edit| } - + } @else { - + } @@ -76,8 +58,7 @@

Activities

edit - } @else { #edit| } - + } @else {
-
+ }
diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html index a97dcd2e16..6fed39bc24 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html @@ -11,31 +11,14 @@

Campuses

Name @if (!editing(campus)) { -
- {{ campus.name }} -
+
+ {{ campus.name }} +
} @else { - -
- - - - - -
- - } - - + } @@ -49,15 +32,14 @@

Campuses

Abbreviation @if (!editing(campus)) { -
- {{ campus.abbreviation }} -
- } @else { #edit| } - +
+ {{ campus.abbreviation }} +
+ } @else { -
+ } @@ -71,11 +53,10 @@

Campuses

Default Sync Mode @if (!editing(campus)) { -
- {{ campus.mode | titlecase }} -
- } @else { #edit| } - +
+ {{ campus.mode | titlecase }} +
+ } @else { Default Sync Mode @@ -86,7 +67,7 @@

Campuses

}
-
+ } @@ -102,18 +83,41 @@

Campuses

+ + + Timezone + + @if (!editing(campus)) { +
+ {{ campus.timezone }} +
+ } @else { + + Timezone + + + + } + + + + Timezone + + + +
+ Active @if (!editing(campus)) { -
- -
- } @else { #edit| } - +
+ +
+ } @else { -
+ } @@ -135,8 +139,7 @@

Campuses

- } @else { #edit| } - + } @else {
-
+ }
diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts index 3ab6b9e71e..1fa8871cc3 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts @@ -18,7 +18,7 @@ export class CampusListComponent extends EntityFormComponent { syncModes = ['timetable', 'automatic', 'manual']; // Set up the table - columns: string[] = ['name', 'abbreviation', 'mode', 'active', 'options']; + columns: string[] = ['name', 'abbreviation', 'mode', 'timezone', 'active', 'options']; campuses: Campus[] = new Array(); dataSource = new MatTableDataSource(this.campuses); @@ -33,6 +33,7 @@ export class CampusListComponent extends EntityFormComponent { abbreviation: new UntypedFormControl('', [Validators.required]), name: new UntypedFormControl('', [Validators.required]), mode: new UntypedFormControl('', [Validators.required]), + timezone: new UntypedFormControl('', [Validators.required]), active: new UntypedFormControl(false), }, 'Campus', @@ -91,6 +92,7 @@ export class CampusListComponent extends EntityFormComponent { case 'name': case 'abbreviation': case 'mode': + case 'timezone': case 'active': return super.sortTableData(sort); } diff --git a/src/app/admin/institution-settings/institution-settings.component.html b/src/app/admin/institution-settings/institution-settings.component.html index fdaa85dddc..590a56f54f 100644 --- a/src/app/admin/institution-settings/institution-settings.component.html +++ b/src/app/admin/institution-settings/institution-settings.component.html @@ -9,6 +9,17 @@ + +
+
+
+

Learning Outcomes

+

Manage global learning outcomes for the institution

+
+
+ +
+
@if (overseerEnabled) { diff --git a/src/app/admin/institution-settings/institution-settings.component.scss b/src/app/admin/institution-settings/institution-settings.component.scss index 8681f6dbfa..7017d84036 100644 --- a/src/app/admin/institution-settings/institution-settings.component.scss +++ b/src/app/admin/institution-settings/institution-settings.component.scss @@ -1,3 +1,16 @@ .institution-settings-container { padding: 0 5rem 0 5rem; } +.learning-outcomes-container { + padding: 0 1rem 1rem 1rem; +} +table { + width: 100%; +} +.header { + display: flex; + .interactions { + margin-left: auto; + margin-top: auto; + } +} diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html index d2e70e730d..9ca1c6a6ba 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html @@ -1,11 +1,28 @@ + + +
{{ data.text }}
+
+
+
-

Overseer Images

+

+ Overseer Images + @if (diskSpace !== null) { + ({{ diskSpace ?? 'N/A' }} GB available) + } +

Add new image or modify existing ones used for automated task analysis

- +
@@ -51,7 +68,9 @@

Overseer Images

@@ -62,7 +81,7 @@

Overseer Images

@@ -80,10 +99,10 @@

Overseer Images

overseerImage.pulledImageStatus === 'success' ? 'green' : overseerImage.pulledImageStatus === 'loading' - ? 'orange' - : overseerImage.pulledImageStatus === 'failed' - ? 'red' - : '' + ? 'orange' + : overseerImage.pulledImageStatus === 'failed' + ? 'red' + : '' }" > @@ -113,7 +133,11 @@

Overseer Images

@@ -39,11 +39,11 @@ @@ -51,7 +51,12 @@ @@ -63,7 +68,9 @@ - + @@ -74,20 +81,49 @@
Name
- +
Last Pulled
- {{ overseerImage.lastPulledDate }} + {{ overseerImage.lastPulledDate | humanizedDate }}
- diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts index 703054827e..05173d587d 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts @@ -1,9 +1,12 @@ -import {Component, ViewChild} from '@angular/core'; -import {MatTableDataSource, MatTable} from '@angular/material/table'; -import {OverseerImage, OverseerImageService} from 'src/app/api/models/doubtfire-model'; -import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {HttpClient} from '@angular/common/http'; +import {AfterViewInit, Component, TemplateRef, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatDialog} from '@angular/material/dialog'; import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {OverseerImage, OverseerImageService} from 'src/app/api/models/doubtfire-model'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; @Component({ @@ -11,7 +14,12 @@ import {AlertService} from 'src/app/common/services/alert.service'; templateUrl: 'overseer-image-list.component.html', styleUrls: ['overseer-image-list.component.scss'], }) -export class OverseerImageListComponent extends EntityFormComponent { +export class OverseerImageListComponent + extends EntityFormComponent + implements AfterViewInit +{ + @ViewChild('textDialog') textDialog!: TemplateRef; + @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; @@ -21,11 +29,16 @@ export class OverseerImageListComponent extends EntityFormComponent { this.pushToTable(response); }); + + this.httpClient.get('/api/admin/disk_space').subscribe({ + next: (diskSpace) => { + this.diskSpace = diskSpace; + }, + }); } // This method is passed to the submit method on the parent @@ -69,8 +88,15 @@ export class OverseerImageListComponent extends EntityFormComponent { - this.loading = false; + this.overseerImageService.pullDockerImage(image).subscribe((job) => { + this.sidekiqProgressModalService + .show(`Pulling image ${image.name} (${image.tag})`, job.id) + .subscribe((_job) => { + this.overseerImageService.fetch(image.id).subscribe((newImage) => { + console.log(newImage); + this.loading = false; + }); + }); }); } @@ -96,4 +122,10 @@ export class OverseerImageListComponent extends EntityFormComponent

Teaching periods

- +
- +
+ + + + + - +
Active @@ -32,6 +43,26 @@

Teaching periods

{{ element.activeUntil | date }} Actions +
+ + + + +
+
- + diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts index 87be5fbef8..f4099456cf 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts @@ -1,13 +1,14 @@ -import { Component, Inject, OnInit, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { MatTableDataSource } from '@angular/material/table'; -import { TeachingPeriodBreak } from 'src/app/api/models/teaching-period'; -import { TeachingPeriod } from 'src/app/api/models/teaching-period'; -import { TeachingPeriodBreakService } from 'src/app/api/services/teaching-period-break.service'; -import { TeachingPeriodService } from 'src/app/api/services/teaching-period.service'; +import {Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTableDataSource} from '@angular/material/table'; +import {TeachingPeriodBreak} from 'src/app/api/models/teaching-period'; +import {TeachingPeriod} from 'src/app/api/models/teaching-period'; +import {TeachingPeriodBreakService} from 'src/app/api/services/teaching-period-break.service'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {TeachingPeriodUnitImportService} from '../teaching-period-unit-import/teaching-period-unit-import.dialog'; +import {AlertService} from 'src/app/common/services/alert.service'; @Component({ selector: 'f-teaching-period-list', @@ -20,8 +21,13 @@ export class TeachingPeriodListComponent implements OnInit { public dataSource = new MatTableDataSource(); - displayedColumns: string[] = ['active', 'name', 'startDate', 'endDate', 'activeUntil']; - constructor(private teachingPeriodsService: TeachingPeriodService, public dialog: MatDialog) {} + displayedColumns: string[] = ['active', 'name', 'startDate', 'endDate', 'activeUntil', 'actions']; + + constructor( + private teachingPeriodsService: TeachingPeriodService, + public dialog: MatDialog, + public teachingPeriodUnitImportService: TeachingPeriodUnitImportService, + ) {} ngOnInit(): void { // update the Teaching Periods @@ -35,6 +41,10 @@ export class TeachingPeriodListComponent implements OnInit { }); } + importUnits(teachingPeriod: TeachingPeriod) { + this.teachingPeriodUnitImportService.openImportUnitsDialog(teachingPeriod); + } + addTeachingPeriod() { this.dialog.open(NewTeachingPeriodDialogComponent, { data: {}, @@ -43,9 +53,42 @@ export class TeachingPeriodListComponent implements OnInit { selectTeachingPeriod(selectedTeachingPeriod: TeachingPeriod) { this.teachingPeriodsService.get(selectedTeachingPeriod.id).subscribe((teachingPeriod) => { - this.dialog.open(NewTeachingPeriodDialogComponent, { data: { teachingPeriod: teachingPeriod } }); + this.dialog.open(NewTeachingPeriodDialogComponent, {data: {teachingPeriod: teachingPeriod}}); }); } + + /** + * Function used by implemented sortTableData to determine the order + * of values within the EntityForm once sorting has been triggered. + * + * @param aValue value to be compared against bValue. + * @param bValue value to be compared against aValue. + * + * @returns truthy comparison between aValue and bValue. + */ + protected sortCompare(aValue: number | string, bValue: number | string, isAsc: boolean) { + return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); + } + + // Sorting function to sort data when sort + // event is triggered + sortTableData(sort: Sort) { + if (!sort.active || sort.direction === '') { + return; + } + switch (sort.active) { + case 'active': + case 'name': + case 'startDate': + case 'endDate': + case 'activeUntil': + this.dataSource.data = this.dataSource.data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + return this.sortCompare(a[sort.active], b[sort.active], isAsc); + }); + return; + } + } } @Component({ @@ -58,18 +101,24 @@ export class NewTeachingPeriodDialogComponent { private dialogRef: MatDialogRef, public teachingPeriodService: TeachingPeriodService, public teachingPeriodBreakService: TeachingPeriodBreakService, - private _snackBar: MatSnackBar + public alertService: AlertService, ) {} public newOrSelectedTeachingPeriod = this.data.teachingPeriod || new TeachingPeriod(); public tempBreak = new TeachingPeriodBreak(); addTeachingBreak() { - this.newOrSelectedTeachingPeriod.addBreak(this.tempBreak.startDate, this.tempBreak.numberOfWeeks).subscribe({ - next: (teachingPeriodBreak) => { - console.log(teachingPeriodBreak); - }, - }); + this.newOrSelectedTeachingPeriod + .addBreak(this.tempBreak.startDate, this.tempBreak.numberOfWeeks) + .subscribe({ + next: (teachingPeriodBreak) => { + this.alertService.success('Break added'); + console.log(teachingPeriodBreak); + }, + error: (response) => { + this.alertService.error(`Error adding break. ${response}`); + }, + }); } deleteBreak(teachingPeriod: TeachingPeriod, teachingBreak: TeachingPeriodBreak): void { @@ -77,26 +126,25 @@ export class NewTeachingPeriodDialogComponent { next: (teachingPeriodBreak) => { console.log(teachingPeriodBreak); }, - error: (response) => {}, + error: (response) => { + this.alertService.error(`Error deleting break. ${response}`); + }, }); } submitTeachingPeriod() { - // todo: use alert service - this.teachingPeriodService.store(this.newOrSelectedTeachingPeriod).subscribe({ + // Check if we are updating or creating a new teaching period + const observer = this.newOrSelectedTeachingPeriod.id + ? this.teachingPeriodService.update(this.newOrSelectedTeachingPeriod) + : this.teachingPeriodService.store(this.newOrSelectedTeachingPeriod); + + // Save the teaching period + observer.subscribe({ next: (teachingPeriod) => { - this._snackBar.open(`${teachingPeriod.name} saved`, 'dismiss', { - duration: 2000, - horizontalPosition: 'end', - verticalPosition: 'top', - }); + this.alertService.success(`${teachingPeriod.name} saved`); }, error: (response) => { - this._snackBar.open(response, 'dismiss', { - duration: 5000, - horizontalPosition: 'end', - verticalPosition: 'top', - }); + this.alertService.error(`Error saving teaching period. ${response}`); }, }); } diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts index 2925b4b59e..53416abcc8 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts @@ -126,6 +126,10 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { public codeChange(code: string, value: UnitImportData) { value.relatedUnits = this.relatedUnits(code); + // add source unit to realted units - so that it is retained on code change + if (value.sourceUnit && !value.relatedUnits.find((u) => u.value.id === value.sourceUnit.id)) { + value.relatedUnits.unshift({value: value.sourceUnit, text: value.sourceUnit.codeAndPeriod}); + } value.sourceUnit = value.relatedUnits.length > 0 ? value.relatedUnits[0].value : null; } @@ -197,36 +201,43 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { } private importExistingUnit(unitToImport: UnitImportData, idx: number) { - unitToImport.sourceUnit.rolloverTo({ teaching_period_id: this.data.teachingPeriod.id }).subscribe({ - next: (newUnit: Unit) => { - unitToImport.done = true; - // Employ the convenor - if (unitToImport.convenor && unitToImport.convenor !== newUnit.mainConvenorUser) { - newUnit.addStaff(unitToImport.convenor, 'Convenor').subscribe({ - next: (newRole) => { - console.log(`Employed ${unitToImport.convenor.name} in ${newUnit.code}`); - newUnit.changeMainConvenor(newRole).subscribe({ - next: () => { - console.log(`Set ${unitToImport.convenor.name} as main convenor in ${newUnit.code}`); - }, - error: (failure) => { - console.log(failure); - }, - }); - }, - error: (failure) => { - console.log(failure); - }, - }); - } - this.importUnit(idx + 1); - }, - error: (failure) => { - console.log(failure); - unitToImport.done = false; - this.importUnit(idx + 1); - }, - }); + unitToImport.sourceUnit + .rolloverTo({ + new_unit_code: unitToImport.unitCode, + teaching_period_id: this.data.teachingPeriod.id, + }) + .subscribe({ + next: (newUnit: Unit) => { + unitToImport.done = true; + // Employ the convenor + if (unitToImport.convenor && unitToImport.convenor !== newUnit.mainConvenorUser) { + newUnit.addStaff(unitToImport.convenor, 'Convenor').subscribe({ + next: (newRole) => { + console.log(`Employed ${unitToImport.convenor.name} in ${newUnit.code}`); + newUnit.changeMainConvenor(newRole).subscribe({ + next: () => { + console.log( + `Set ${unitToImport.convenor.name} as main convenor in ${newUnit.code}`, + ); + }, + error: (failure) => { + console.log(failure); + }, + }); + }, + error: (failure) => { + console.log(failure); + }, + }); + } + this.importUnit(idx + 1); + }, + error: (failure) => { + console.log(failure); + unitToImport.done = false; + this.importUnit(idx + 1); + }, + }); } private createNewUnit(unitToImport: UnitImportData, idx: number) { diff --git a/src/app/api/models/campus/campus.ts b/src/app/api/models/campus/campus.ts index 164b3704f6..9491e29e53 100644 --- a/src/app/api/models/campus/campus.ts +++ b/src/app/api/models/campus/campus.ts @@ -7,6 +7,7 @@ export class Campus extends Entity { name: string; mode: campusModes; abbreviation: string; + timezone: string; public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { return { diff --git a/src/app/api/models/d2l/d2l_assessment_mapping.service.ts b/src/app/api/models/d2l/d2l_assessment_mapping.service.ts new file mode 100644 index 0000000000..3f2fe47087 --- /dev/null +++ b/src/app/api/models/d2l/d2l_assessment_mapping.service.ts @@ -0,0 +1,23 @@ +import {Injectable} from '@angular/core'; +import {EntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {D2lAssessmentMapping} from './d2l_assessment_mapping'; +import {Unit} from '../doubtfire-model'; + +@Injectable() +export class D2lAssessmentMappingService extends EntityService { + protected readonly endpointFormat = 'units/:unitId:/d2l/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys('id', 'orgUnitId', 'gradeObjectId'); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public createInstanceFrom(_json: object, other: Unit): D2lAssessmentMapping { + return new D2lAssessmentMapping(other); + } +} diff --git a/src/app/api/models/d2l/d2l_assessment_mapping.ts b/src/app/api/models/d2l/d2l_assessment_mapping.ts new file mode 100644 index 0000000000..ac228bdbb6 --- /dev/null +++ b/src/app/api/models/d2l/d2l_assessment_mapping.ts @@ -0,0 +1,15 @@ +import {Entity} from 'ngx-entity-service'; +import {Unit} from '../unit'; + +export class D2lAssessmentMapping extends Entity { + id: number; + unit: Unit; + + orgUnitId: string; + gradeObjectId: string; + + constructor(unit: Unit) { + super(); + this.unit = unit; + } +} diff --git a/src/app/api/models/discussion-prompt.ts b/src/app/api/models/discussion-prompt.ts new file mode 100644 index 0000000000..e984847084 --- /dev/null +++ b/src/app/api/models/discussion-prompt.ts @@ -0,0 +1,59 @@ +import {Entity} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DiscussionPromptService} from '../services/discussion-prompt.service'; +import {Project, TaskDefinition, Unit, User} from './doubtfire-model'; + +export class DiscussionPrompt extends Entity { + id: number; + unit: Unit; + taskDefinition: TaskDefinition; + project: Project | null; + createdBy: User; + content: string; + priority: number; + discussedAt: Date; + + public readonly PRIORITY = { + 1: 'Low', + 2: 'Medium', + 3: 'High', + } as const; + + constructor(data?: Project | TaskDefinition | Unit) { + super(); + if (data) { + if (data instanceof Project) { + this.project = data; + } else if (data instanceof TaskDefinition) { + this.taskDefinition = data; + } else if (data instanceof Unit) { + this.unit = data; + } + } else { + console.error('Failed to get project'); + } + } + + public get priorityLabel() { + return this.PRIORITY[this.priority] ?? this.priority; + } + + public delete() { + const discussionPromptService: DiscussionPromptService = + AppInjector.get(DiscussionPromptService); + discussionPromptService + .delete( + {task_definition_id: this.taskDefinition.id, id: this.id}, + {cache: this.taskDefinition.discussionPromptsCache}, + ) + .subscribe({ + next: (_response: object) => { + AppInjector.get(AlertService).success('Successfully deleted discussion note', 4000); + }, + error: (error: any) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index 3cb4911083..ed485c939a 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -32,6 +32,12 @@ export * from './task-comment/discussion-comment'; export * from '../services/task-outcome-alignment.service'; export * from './task-similarity'; export * from './tii-action'; +export * from './scorm-datamodel'; +export * from './scorm-player-context'; +export * from './test-attempt'; +export * from './task-comment/scorm-comment'; +export * from './task-comment/scorm-extension-comment'; +export * from './feedback-template'; // Users -- are students or staff export * from './user/user'; @@ -39,7 +45,6 @@ export * from './user/user'; // WebCal -- calendars used to track task due dates export * from './webcal/webcal'; - export * from '../services/authentication.service'; export * from '../services/unit.service'; export * from '../services/project.service'; @@ -56,3 +61,6 @@ export * from '../services/teaching-period-break.service'; export * from '../services/learning-outcome.service'; export * from '../services/group-set.service'; export * from '../services/task-similarity.service'; +export * from '../services/test-attempt.service'; +export * from '../models/d2l/d2l_assessment_mapping.service'; +export * from '../services/feedback-template.service'; diff --git a/src/app/api/models/feedback-template.ts b/src/app/api/models/feedback-template.ts new file mode 100644 index 0000000000..1634cb70d6 --- /dev/null +++ b/src/app/api/models/feedback-template.ts @@ -0,0 +1,72 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {FeedbackTemplateService} from '../services/feedback-template.service'; + +export class FeedbackTemplate extends Entity { + id: number; + type: 'group' | 'template'; + chipText: string; + description: string; + commentText: string; + summaryText: string; + taskStatus: 'fix_and_resubmit' | 'discuss' | 'redo' | 'complete' | 'feedback_exceeded'; + parentChipId: number; + learningOutcomeId: number; + + public save(): Observable { + const svc = AppInjector.get(FeedbackTemplateService); + + if (this.isNew) { + return svc + .create({}, {entity: this, endpointFormat: FeedbackTemplateService.addEndpoint}) + .pipe( + tap((response: FeedbackTemplate) => { + Object.assign(this, response); + }), + ); + } else { + return svc + .update( + {id: this.id}, + {entity: this, endpointFormat: FeedbackTemplateService.updateEndpoint}, + ) + .pipe( + tap((response: FeedbackTemplate) => { + Object.assign(this, response); + }), + ); + } + } + + private originalSaveData: string; + + public get hasOriginalSaveData(): boolean { + return this.originalSaveData !== undefined && this.originalSaveData !== null; + } + + public setOriginalSaveData(mapping: EntityMapping) { + this.originalSaveData = JSON.stringify(this.toJson(mapping)); + } + + public hasChanges(mapping: EntityMapping): boolean { + if (!this.originalSaveData) { + return false; + } + + return this.originalSaveData != JSON.stringify(this.toJson(mapping)); + } + + public get isNew(): boolean { + return !this.id; + } + + public delete(): Observable { + const svc = AppInjector.get(FeedbackTemplateService); + + return svc.delete( + {id: this.id}, + {entity: this, endpointFormat: FeedbackTemplateService.updateEndpoint}, + ); + } +} diff --git a/src/app/api/models/learning-outcome.ts b/src/app/api/models/learning-outcome.ts index 40a19d893a..dfdc55fa19 100644 --- a/src/app/api/models/learning-outcome.ts +++ b/src/app/api/models/learning-outcome.ts @@ -1,12 +1,158 @@ -import { Entity } from 'ngx-entity-service'; - +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {LearningOutcomeService, TaskDefinition, Unit} from './doubtfire-model'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; export class LearningOutcome extends Entity { - id: number; - iloNumber: number; + contextType: string; + contextId: number; abbreviation: string; - name: string; - description: string; + shortDescription: string; + fullOutcomeDescription: string; + linkedOutcomeIds: number[] = []; + + context?: TaskDefinition | Unit; + + private readonly contextTypePath = { + 'Unit': 'units', + 'TaskDefinition': 'task_definitions', + 'Course': 'courses', + }; + + public save(): Observable { + const svc = AppInjector.get(LearningOutcomeService); + + if (this.context) { + if (this.isNew) { + return svc + .create( + { + contextType: this.contextTypePath[this.contextType], + contextId: this.contextId, + }, + { + entity: this, + cache: this.context.learningOutcomesCache, + }, + ) + .pipe( + tap((response: LearningOutcome) => { + Object.assign(this, response); + }), + ); + } else { + return svc + .update( + { + contextType: this.contextTypePath[this.contextType], + contextId: this.contextId, + id: this.id, + }, + { + entity: this, + cache: this.context.learningOutcomesCache, + endpointFormat: LearningOutcomeService.updateEndpoint, + }, + ) + .pipe( + tap((response: LearningOutcome) => { + Object.assign(this, response); + }), + ); + } + } else { + // GLO + if (this.isNew) { + return svc + .create({}, {entity: this, endpointFormat: LearningOutcomeService.globalEndpoint}) + .pipe( + tap((response: LearningOutcome) => { + Object.assign(this, response); + }), + ); + } else { + return svc + .update( + { + id: this.id, + }, + { + entity: this, + endpointFormat: LearningOutcomeService.updateGlobalEndpoint, + }, + ) + .pipe( + tap((response: LearningOutcome) => { + Object.assign(this, response); + }), + ); + } + } + } + + private originalSaveData: string; + + public get hasOriginalSaveData(): boolean { + return this.originalSaveData !== undefined && this.originalSaveData !== null; + } + + /** + * To check if things have changed, we need to get the initial save data... as it + * isn't empty by default. We can then use + * this to check if there are changes. + * + * @param mapping the mapping to get changes + */ + public setOriginalSaveData(mapping: EntityMapping) { + this.originalSaveData = JSON.stringify(this.toJson(mapping)); + } + + public hasChanges(mapping: EntityMapping): boolean { + if (!this.originalSaveData) { + return false; + } + + return this.originalSaveData != JSON.stringify(this.toJson(mapping)); + } + + public get isNew(): boolean { + return !this.id; + } + + public delete(): Observable { + const svc = AppInjector.get(LearningOutcomeService); + + if (this.context) { + return svc.delete( + { + contextType: this.contextTypePath[this.contextType], + contextId: this.contextId, + id: this.id, + }, + { + entity: this, + cache: this.context.learningOutcomesCache, + endpointFormat: LearningOutcomeService.updateEndpoint, + }, + ); + } else { + // GLO + return svc.delete( + { + id: this.id, + }, + { + entity: this, + endpointFormat: LearningOutcomeService.updateGlobalEndpoint, + }, + ); + } + } + public getFeedbackTemplateBatchUploadUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/${this.contextTypePath[this.contextType]}/${this.contextId}/outcomes/${this.id}/feedback_chips/csv`; + } } diff --git a/src/app/api/models/marking-session.ts b/src/app/api/models/marking-session.ts new file mode 100644 index 0000000000..8bfbe3a446 --- /dev/null +++ b/src/app/api/models/marking-session.ts @@ -0,0 +1,40 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {User} from './doubtfire-model'; +import {Unit} from './unit'; + +export class MarkingSession extends Entity { + id: number; + + // Marking tutor + user: User; + + unit: Unit; + + startTime: Date; + endTime: Date; + duringTutorial: boolean; + durationMinutes: number; + + // Aggregated session activities count + commentsAdded: number; + assessments: number; + submissionsOpened: number; + + constructor(data?: Unit) { + super(); + if (data) { + this.unit = data; + } else { + console.error('Failed to get unit'); + } + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + markingSession: super.toJson(mappingData, ignoreKeys), + }; + } +} diff --git a/src/app/api/models/overseer/overseer-assessment.ts b/src/app/api/models/overseer/overseer-assessment.ts index 7ca6d62464..a41bcbb5d2 100644 --- a/src/app/api/models/overseer/overseer-assessment.ts +++ b/src/app/api/models/overseer/overseer-assessment.ts @@ -1,30 +1,63 @@ -import { Entity, EntityMapping } from 'ngx-entity-service'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Task} from '../doubtfire-model'; +import {OverseerStepResult} from './overseer-step-result'; export class OverseerAssessment extends Entity { id: number; + // overseerStepId: number; timestamp: Date; timestampString: string; - content?: [{ label: string; result: string }]; - task?: any; - taskStatus?: any; - submissionStatus?: any; - createdAt?: any; - updatedAt?: any; - taskId?: any; + content?: [{label: string; result: string}]; + task?: Task; + taskStatus?: string; + submissionStatus?: 'queued' | 'executing' | 'passed' | 'failed' | 'error'; + createdAt?: Date; + updatedAt?: Date; + taskId?: number; + + totalSteps: number; + passedSteps: number; label: string; + hasSubmissionFiles?: boolean; + + public readonly stepResultsCache: EntityCache = + new EntityCache(); - constructor(task?: object) { + constructor(task?: Task) { super(); - if ( task ) { + if (task) { this.task = task; } } - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { - overseer_assessment: super.toJson(mappingData, ignoreKeys) + overseer_assessment: super.toJson(mappingData, ignoreKeys), }; } + + public get stepsSkipped() { + return this.task?.definition.overseerStepsCache.currentValues.filter( + (step) => + !this.stepResultsCache.currentValues.find((result) => result.overseerStepId === step.id), + ); + } + + public get reportReady() { + return this.submissionStatus === 'passed' || this.submissionStatus === 'failed'; + } + + public submissionFilesUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + const timestamp = + this.timestampString ?? Math.floor(this.timestamp.getTime() / 1000).toString(); + return `${constants.API_URL}/projects/${this.task.project.id}/task_def_id/${this.task.definition.id}/submissions/timestamps/${timestamp}/files`; + } } diff --git a/src/app/api/models/overseer/overseer-step-result.ts b/src/app/api/models/overseer/overseer-step-result.ts new file mode 100644 index 0000000000..2a44371825 --- /dev/null +++ b/src/app/api/models/overseer/overseer-step-result.ts @@ -0,0 +1,35 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {OverseerAssessment} from './overseer-assessment'; +import {OverseerStep} from './overseer-step'; + +export class OverseerStepResult extends Entity { + id: number; + overseerAssessment: OverseerAssessment; + overseerStep: OverseerStep; + overseerStepId: number; + + exitStatus: number; + pass: boolean; + stdout: string; + stdin: string; + expectedOutput: string; + stdoutSha256: string; + stdinSha256: string; + expectedOutputSha256: string; + feedbackMessage: string; + + constructor(oa?: OverseerAssessment, os?: OverseerStep) { + super(); + this.overseerAssessment = oa; + // this.overseerStep = os; + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + overseer_step_result: super.toJson(mappingData, ignoreKeys), + }; + } +} diff --git a/src/app/api/models/overseer/overseer-step.ts b/src/app/api/models/overseer/overseer-step.ts new file mode 100644 index 0000000000..6fa14bf1bf --- /dev/null +++ b/src/app/api/models/overseer/overseer-step.ts @@ -0,0 +1,77 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {TaskDefinition} from '../task-definition'; +import {TaskStatus, TaskStatusEnum} from '../task-status'; +import {OverseerStepService} from '../../services/overseer-step.service'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; + +export class OverseerStep extends Entity { + id: number; + taskDefinition: TaskDefinition; + + name: string; + description: string; + + // Shown to the student's + displayName: string; + displayDescription: string; + + runCommand: string; + decodedRunCommand: string; + + commandLanguage: string; + timeout: number; + sortOrder: number; + stepType: 'status_check' | 'output_diff'; + partialOutputDiff: boolean; + stdinInputFile: string; + expectedOutputFile: string; + + feedbackMessage: string; + statusOnSuccess: TaskStatusEnum | 'no_change'; + statusOnFailure: TaskStatusEnum | 'no_change'; + + haltOnSuccess: boolean; + haltOnFailure: boolean; + + showExpectedOutput: boolean; + showStdin: boolean; + showStdout: boolean; + + enabled: boolean; + + // showStdOutToStudent: boolean + + constructor(td?: TaskDefinition) { + super(); + this.taskDefinition = td; + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + overseer_step: super.toJson(mappingData, ignoreKeys), + }; + } + + public delete() { + const overseerStepService: OverseerStepService = AppInjector.get(OverseerStepService); + overseerStepService + .delete( + { + id: this.id, + }, + {cache: this.taskDefinition.overseerStepsCache, endpointFormat: 'overseer_steps/:id:'}, + ) + .subscribe({ + next: (_response: object) => { + AppInjector.get(AlertService).success('Successfully deleted overseer step', 4000); + }, + error: (error) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index bde396b74b..b799ed01d6 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -23,6 +23,7 @@ import { } from './doubtfire-model'; import { TaskOutcomeAlignment } from './task-outcome-alignment'; import { AlertService } from 'src/app/common/services/alert.service'; +import { StaffNote } from './staff-note'; export class Project extends Entity { public id: number; @@ -38,9 +39,13 @@ export class Project extends Entity { public portfolioAvailable: boolean; public usesDraftLearningSummary: boolean; + public specConDays: number = 0; + public hasPortfolio: boolean; public portfolioStatus: number; - public portfolioFiles: { kind: string; name: string; idx: number }[]; + public portfolioFiles: {kind: string; name: string; idx: number}[]; + public escalationAttemptsRemaining: number; + public portfolioSubmissionDate: Date; public taskStats: { key: TaskStatusEnum; @@ -50,6 +55,7 @@ export class Project extends Entity { public burndownChartData: { key: string; values: number[] }[]; public readonly taskCache: EntityCache = new EntityCache(); + public readonly staffNoteCache: EntityCache = new EntityCache(); public readonly tutorialEnrolmentsCache: EntityCache = new EntityCache(); public readonly groupCache: EntityCache = new EntityCache(); public readonly taskOutcomeAlignmentsCache: EntityCache = @@ -60,6 +66,8 @@ export class Project extends Entity { public similarityFlag: boolean = false; + public staffNoteCount: number; + public constructor(unit?: Unit) { super(); this.unit = unit; @@ -177,13 +185,13 @@ export class Project extends Entity { public calcTopTasks() { // We will assign current weight to tasks... - var currentWeight: number = 0; + let currentWeight: number = 0; // Assign weights to tasks in final state - complete, fail, etc const sortedCompletedTasks: Task[] = this.taskCache.currentValues .filter((task) => task.inFinalState()) .sort((a, b) => a.definition.seq - b.definition.seq) - .sort((a, b) => a.definition.startDate.getTime() - b.definition.startDate.getTime()); + .sort((a, b) => a.startDate.getTime() - b.startDate.getTime()); sortedCompletedTasks.forEach((task) => { task.topWeight = currentWeight; @@ -193,8 +201,8 @@ export class Project extends Entity { // Sort valid top tasks by start date - tasks in non-final state const sortedTasks: Task[] = this.taskCache.currentValues .filter((task) => task.isValidTopTask()) - .sort((a, b) => a.definition.seq - b.definition.seq) - .sort((a, b) => a.definition.startDate.getTime() - b.definition.startDate.getTime()); + .sort((a, b) => a.startDate.getTime() - b.startDate.getTime()) + .sort((a, b) => a.definition.seq - b.definition.seq); const overdueTasks: Task[] = sortedTasks.filter((task) => task.daysUntilDueDate() <= 7); @@ -215,7 +223,7 @@ export class Project extends Entity { const toAdd: Task[] = sortedTasks .filter((task) => task.daysUntilDueDate() > 7) .sort((a, b) => a.definition.targetGrade - b.definition.targetGrade) - .sort((a, b) => a.definition.startDate.getTime() - b.definition.startDate.getTime()); + .sort((a, b) => a.startDate.getTime() - b.startDate.getTime()); // Sort by the targetGrade. Pass task are done first if same due date as others. @@ -229,7 +237,7 @@ export class Project extends Entity { public assignGrade(score: number, rationale: string): void { const alerts = AppInjector.get(AlertService); const projectService: ProjectService = AppInjector.get(ProjectService); - const oldGrade: number = this.grade; + const oldGrade: number = this.grade || 0; this.grade = score; this.gradeRationale = rationale; @@ -407,7 +415,7 @@ export class Project extends Entity { const tasks = this.tasks; const readyOrCompleteTasks = tasks.filter((task) => - ['ready_for_feedback', 'discuss', 'demonstrate', 'complete'].includes(task.status), + ['ready_for_feedback', 'discuss', 'demonstrate', 'complete', 'assess_in_portfolio'].includes(task.status), ); let lastTargetDate: Date; @@ -513,4 +521,35 @@ export class Project extends Entity { this.burndownChartData = result; } + + public applySpecCon(days: number): Observable { + const projectService: ProjectService = AppInjector.get(ProjectService); + return projectService.update(this, {body: {spec_con_days: days}, endpointFormat: 'projects/:id:/spec_con'}).pipe( + tap((project: Project) => { + project.specConDays = days; + }), + ); + } + + public tasksIncludedInPortfolioUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.id}/portfolio_tasks`; + } + + public getTasksIncludedInPortfolio(): Observable { + const httpClient = AppInjector.get(HttpClient); + return httpClient.get(this.tasksIncludedInPortfolioUrl()); + } + + public resetTargetDates(): Observable { + const projectService: ProjectService = AppInjector.get(ProjectService); + return projectService.update( + { + projectId: this.id, + }, + { + endpointFormat: '/projects/:projectId:/reset_target_dates', + entity: this, + }, + ); + } } diff --git a/src/app/api/models/scorm-datamodel.ts b/src/app/api/models/scorm-datamodel.ts new file mode 100644 index 0000000000..0fdc2d3a06 --- /dev/null +++ b/src/app/api/models/scorm-datamodel.ts @@ -0,0 +1,50 @@ +export class ScormDataModel { + dataModel: {[key: string]: any} = {}; + readonly msgPrefix = 'SCORM DataModel: '; + + constructor() { + this.dataModel = {}; + } + + public restore(dataModel: string) { + // console.log(this.msgPrefix + 'restoring DataModel with provided data'); + this.dataModel = JSON.parse(dataModel); + } + + public get(key: string): string { + // console.log(`SCORM DataModel: get ${key} ${this.dataModel[key]}`); + return this.dataModel[key] ?? ''; + } + + public dump(): {[key: string]: any} { + return this.dataModel; + } + + public set(key: string, value: any): string { + // console.log(this.msgPrefix + 'set: ', key, value); + this.dataModel[key] = value; + if (key.match('cmi.interactions.\\d+.id')) { + // cmi.interactions._count must be incremented after a new interaction is created + const interactionPath = key.match('cmi.interactions.\\d+'); + const objectivesCounterForInteraction = interactionPath.toString() + '.objectives._count'; + // console.log('Incrementing cmi.interactions._count'); + this.dataModel['cmi.interactions._count']++; + // cmi.interactions.n.objectives._count must be initialized after an interaction is created + // console.log(`Initializing ${objectivesCounterForInteraction}`); + this.dataModel[objectivesCounterForInteraction] = 0; + } + if (key.match('cmi.interactions.\\d+.objectives.\\d+.id')) { + const interactionPath = key.match('cmi.interactions.\\d+.objectives'); + const objectivesCounterForInteraction = interactionPath.toString() + '._count'; + // cmi.interactions.n.objectives._count must be incremented after objective creation + // console.log(`Incrementing ${objectivesCounterForInteraction}`); + this.dataModel[objectivesCounterForInteraction.toString()]++; + } + if (key.match('cmi.objectives.\\d+.id')) { + // cmi.objectives._count must be incremented after a new objective is created + // console.log('Incrementing cmi.objectives._count'); + this.dataModel['cmi.objectives._count']++; + } + return 'true'; + } +} diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts new file mode 100644 index 0000000000..e8eed9b12e --- /dev/null +++ b/src/app/api/models/scorm-player-context.ts @@ -0,0 +1,66 @@ +import {User} from 'src/app/api/models/doubtfire-model'; + +type DataModelState = 'Uninitialized' | 'Initialized' | 'Terminated'; + +type DataModelError = Record; +const CMIErrorCodes: DataModelError = { + 0: 'No Error', + 101: 'General Exception', + 102: 'General Initialization Failure', + 103: 'Already Initialized', + 104: 'Content Instance Terminated', + 111: 'General Termination Failure', + 112: 'Termination Before Initialization', + 113: 'Termination After Termination', + 122: 'Retrieve Data Before Initialization', + 123: 'Retrieve Data After Termination', + 132: 'Store Data Before Initialization', + 133: 'Store Data After Termination', + 142: 'Commit Before Initialization', + 143: 'Commit After Termination', + 201: 'General Argument Error', + 301: 'General Get Failure', + 351: 'General Set Failure', + 391: 'General Commit Failure', + 401: 'Undefined Data Model Element', + 402: 'Unimplemented Data Model Element', + 403: 'Data Model Element Value Not Initialized', + 404: 'Data Model Element Is Read Only', + 405: 'Data Model Element Is Write Only', + 406: 'Data Model Element Type Mismatch', + 407: 'Data Model Element Value Out Of Range', + 408: 'Data Model Dependency Not Established', +}; + +export class ScormPlayerContext { + mode: 'browse' | 'normal' | 'review' | 'preview'; + state: DataModelState; + + private _errorCode: number; + get errorCode() { + return this._errorCode; + } + set errorCode(value: number) { + this._errorCode = value; + } + + getErrorMessage(value: string): string { + return CMIErrorCodes[value]; + } + + projectId: number; + taskDefId: number; + user: User; + + attemptId: number; + learnerName: string; + learnerId: number; + + constructor(user: User) { + this.user = user; + this.learnerId = user.id; + this.learnerName = user.firstName + ' ' + user.lastName; + this.state = 'Uninitialized'; + this.errorCode = 0; + } +} diff --git a/src/app/api/models/sidekiq-job.ts b/src/app/api/models/sidekiq-job.ts new file mode 100644 index 0000000000..127db2062e --- /dev/null +++ b/src/app/api/models/sidekiq-job.ts @@ -0,0 +1,19 @@ +import {Entity} from 'ngx-entity-service'; + +export class SidekiqJob extends Entity { + id: string; + status: 'queued' | 'working' | 'retrying' | 'complete' | 'stopped' | 'failed' | 'interrupted'; + message?: string; + + pctComplete: number; + processedCount?: number; + totalCount?: number; + + jobClass: string; // name of the job, eg "StudentImportJob" + + // Custom data unique to each job + result?: string; + + createdAt: number; + updatedAt: number; +} diff --git a/src/app/api/models/staff-note.ts b/src/app/api/models/staff-note.ts new file mode 100644 index 0000000000..bcd1b00e34 --- /dev/null +++ b/src/app/api/models/staff-note.ts @@ -0,0 +1,54 @@ +import {Entity} from 'ngx-entity-service'; +import {Project, Unit, User, UserService} from './doubtfire-model'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {StaffNoteService} from '../services/staff-note.service'; + +export class StaffNote extends Entity { + id: number; + + project: Project; + user: User; + note: string; + replyTo?: StaffNote; + replyToId: number; + createdAt: Date; + updatedAt: Date; + + constructor(data?: Project) { + super(); + if (data) { + this.project = data; + } else { + console.error('Failed to get project'); + } + } + + /** + * Provide the project id to allow mapping in service. + */ + public get projectId(): number { + return this.project.id; + } + + public get authorIsMe(): boolean { + const userService: UserService = AppInjector.get(UserService); + return this.user.id === userService.currentUser.id; + } + + public delete() { + const staffNoteService: StaffNoteService = AppInjector.get(StaffNoteService); + staffNoteService + .delete({projectId: this.project.id, id: this.id}, {cache: this.project.staffNoteCache}) + .subscribe({ + next: (response: object) => { + AppInjector.get(AlertService).error('Successfully deleted staff note', 4000); + this.project.staffNoteCount--; + staffNoteService.updateStaffNoteReplies(this.project.staffNoteCache.currentValues); + }, + error: (error: any) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/task-comment/scorm-comment.ts b/src/app/api/models/task-comment/scorm-comment.ts new file mode 100644 index 0000000000..b15a2c50c8 --- /dev/null +++ b/src/app/api/models/task-comment/scorm-comment.ts @@ -0,0 +1,12 @@ +import {Task, TaskComment, TestAttempt} from '../doubtfire-model'; + +export class ScormComment extends TaskComment { + testAttempt: TestAttempt; + + // UI rendering data + lastInScormSeries: boolean = false; + + constructor(task: Task) { + super(task); + } +} diff --git a/src/app/api/models/task-comment/scorm-extension-comment.ts b/src/app/api/models/task-comment/scorm-extension-comment.ts new file mode 100644 index 0000000000..b8aac7909b --- /dev/null +++ b/src/app/api/models/task-comment/scorm-extension-comment.ts @@ -0,0 +1,33 @@ +import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; +import {AppInjector} from 'src/app/app-injector'; +import {TaskCommentService} from '../../services/task-comment.service'; +import {TaskComment, Task} from '../doubtfire-model'; + +export class ScormExtensionComment extends TaskComment { + assessed: boolean; + granted: boolean; + dateAssessed: Date; + taskScormExtensions: number; + + constructor(task: Task) { + super(task); + } + + private assessScormExtension(): Observable { + const tcs: TaskCommentService = AppInjector.get(TaskCommentService); + return tcs.assessScormExtension(this).pipe( + tap((tc: TaskComment) => { + const scormExtension: ScormExtensionComment = tc as ScormExtensionComment; + + const task = tc.task; + task.scormExtensions = scormExtension.taskScormExtensions; + }), + ); + } + + public grant(): Observable { + this.granted = true; + return this.assessScormExtension(); + } +} diff --git a/src/app/api/models/task-comment/task-comment.ts b/src/app/api/models/task-comment/task-comment.ts index 03b7ea4559..5d49c9ef9f 100644 --- a/src/app/api/models/task-comment/task-comment.ts +++ b/src/app/api/models/task-comment/task-comment.ts @@ -1,10 +1,10 @@ -import { AppInjector } from 'src/app/app-injector'; -import { Entity } from 'ngx-entity-service'; -import { Project, Task, TaskCommentService, User } from 'src/app/api/models/doubtfire-model'; -import { UserService } from '../../services/user.service'; -import API_URL from 'src/app/config/constants/apiURL'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {AppInjector} from 'src/app/app-injector'; +import {Entity} from 'ngx-entity-service'; +import {Project, Task, TaskCommentService, User} from 'src/app/api/models/doubtfire-model'; +import {UserService} from '../../services/user.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AlertService} from 'src/app/common/services/alert.service'; export class TaskComment extends Entity { // Linked objects @@ -19,7 +19,7 @@ export class TaskComment extends Entity { recipient: User; createdAt: Date; recipientReadTime: string; - commentType: string = "text"; + commentType: string = 'text'; isNew: boolean; replyToId: number; @@ -68,7 +68,10 @@ export class TaskComment extends Entity { public delete() { const tcs: TaskCommentService = AppInjector.get(TaskCommentService); tcs - .delete({ projectId: this.project.id, taskDefinitionId: this.task.definition.id, id: this.id }, { cache: this.task.commentCache }) + .delete( + {projectId: this.project.id, taskDefinitionId: this.task.definition.id, id: this.id}, + {cache: this.task.commentCache}, + ) .subscribe({ next: (response: object) => { // this.task.comments = this.task.comments.filter((e: TaskComment) => e.id !== this.id); @@ -76,12 +79,11 @@ export class TaskComment extends Entity { }, error: (error: any) => { AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); - } - } - ); + }, + }); } public get attachmentUrl(): string { - return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.project.id}/task_def_id/${this.task.definition.id}/comments/${this.id}?as_attachment=false` + return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.project.id}/task_def_id/${this.task.definition.id}/comments/${this.id}?as_attachment=false`; } } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 1b49a2e856..c8f88d1e9e 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -1,14 +1,25 @@ -import { HttpClient } from '@angular/common/http'; -import { Entity, EntityMapping } from 'ngx-entity-service'; -import { Observable, tap } from 'rxjs'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { Grade, GroupSet, TutorialStream, Unit } from './doubtfire-model'; -import { TaskDefinitionService } from '../services/task-definition.service'; - -export type UploadRequirement = { key: string; name: string; type: string; tiiCheck?: boolean; tiiPct?: number }; +import {HttpClient} from '@angular/common/http'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {TaskDefinitionService} from '../services/task-definition.service'; +import {Grade, GroupSet, LearningOutcome, Project, TutorialStream, Unit} from './doubtfire-model'; +import {Task} from './doubtfire-model'; +import {TaskPrerequisite} from './task-prerequisite'; +import {DiscussionPrompt} from './discussion-prompt'; +import {OverseerStep} from './overseer/overseer-step'; + +export type UploadRequirement = { + key: string; + name: string; + type: string; + tiiCheck?: boolean; + tiiPct?: number; +}; -export type SimilarityCheck = { key: string; type: string; pattern: string }; +export type SimilarityCheck = {key: string; type: string; pattern: string}; export class TaskDefinition extends Entity { id: number; @@ -21,7 +32,7 @@ export class TaskDefinition extends Entity { targetDate: Date; dueDate: Date; startDate: Date; - uploadRequirements: UploadRequirement[]; + uploadRequirements: UploadRequirement[] = []; tutorialStream: TutorialStream = null; plagiarismChecks: SimilarityCheck[] = []; plagiarismReportUrl: string; @@ -31,12 +42,46 @@ export class TaskDefinition extends Entity { groupSet: GroupSet = null; hasTaskSheet: boolean; hasTaskResources: boolean; + scormEnabled: boolean; + hasScormData: boolean; + scormAllowReview: boolean; + scormBypassTest: boolean; + scormTimeDelayEnabled: boolean; + scormAttemptLimit: number = 0; hasTaskAssessmentResources: boolean; + hasTaskAssessmentScript: boolean; isGraded: boolean; maxQualityPts: number; overseerImageId: number; assessmentEnabled: boolean; - mossLanguage: string = 'moss c'; + similarityLanguage: string = 'c'; + hasJplagReport: boolean; + assessInPortfolioOnly: boolean; + requiresDiscussion: boolean; + useResourcesForJplagBaseCode: boolean; + lockAssessmentsToTutorialStream: boolean; + discussionPromptsCount: number; + overseerResourceFiles: string[] = []; + + // pTargetDate: Date; + cTargetDate: Date; + dTargetDate: Date; + hdTargetDate: Date; + + cStartDate: Date; + dStartDate: Date; + hdStartDate: Date; + + public readonly taskPrerequisitesCache: EntityCache = + new EntityCache(); + + public readonly discussionPromptsCache: EntityCache = + new EntityCache(); + + public readonly learningOutcomesCache: EntityCache = + new EntityCache(); + + public readonly overseerStepsCache: EntityCache = new EntityCache(); readonly unit: Unit; @@ -67,7 +112,7 @@ export class TaskDefinition extends Entity { entity: this, cache: this.unit.taskDefinitionCache, constructorParams: this.unit, - } + }, ); } else { return svc.update( @@ -75,7 +120,7 @@ export class TaskDefinition extends Entity { unitId: this.unit.id, id: this.id, }, - { entity: this } + {entity: this}, ); } } @@ -105,6 +150,21 @@ export class TaskDefinition extends Entity { return this.originalSaveData != JSON.stringify(this.toJson(mapping)); } + public refresh(): void { + const alerts = AppInjector.get(AlertService); + AppInjector.get(TaskDefinitionService) + .fetch({ + unitId: this.unit.id, + id: this.id, + }) + .subscribe({ + next: (taskDefinition) => { + console.log(taskDefinition.name); + }, + error: (message) => alerts.error(message, 6000), + }); + } + public get isNew(): boolean { return !this.id; } @@ -121,8 +181,19 @@ export class TaskDefinition extends Entity { return this.dueDate; } + public get dueWeek(): number { + const startDate = this.unit.startDate; + const dueDate = this.localDueDate() || this.unit.endDate; + + const diffInMs = dueDate.getTime() - startDate.getTime(); + return Math.ceil(diffInMs / (1000 * 60 * 60 * 24 * 7)); // Convert ms to weeks + } + public matches(text: string): boolean { - return this.abbreviation.toLowerCase().indexOf(text) !== -1 || this.name.toLowerCase().indexOf(text) !== -1; + return ( + this.abbreviation.toLowerCase().indexOf(text) !== -1 || + this.name.toLowerCase().indexOf(text) !== -1 + ); } /** @@ -152,6 +223,30 @@ export class TaskDefinition extends Entity { }`; } + public getScormDataUrl(asAttachment: boolean = false) { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/scorm_data.json${ + asAttachment ? '?as_attachment=true' : '' + }`; + } + + public getOutcomeBatchUploadUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/task_definitions/${this.id}/outcomes/csv`; + } + + public getFeedbackTemplateBatchUploadUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/task_definitions/${this.id}/feedback_chips/csv`; + } + + /** + * Open the SCORM test in a new tab - using preview mode. + */ + public previewScormTest(): void { + window.open(`#/task_def_id/${this.id}/preview-scorm`, '_blank'); + } + public get targetGradeText(): string { return Grade.GRADES[this.targetGrade]; } @@ -160,7 +255,7 @@ export class TaskDefinition extends Entity { return this.plagiarismChecks?.length > 0; } - public get needsMoss(): boolean { + public get needsJplag(): boolean { return this.uploadRequirements.some((upreq) => upreq.type === 'code' && upreq.tiiCheck); } @@ -176,18 +271,38 @@ export class TaskDefinition extends Entity { }/task_resources`; } - public get taskAssessmentResourcesUploadUrl(): string { + public get scormDataUploadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ + this.id + }/scorm_data`; + } + + public get taskPrerequisiteUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ + this.id + }/prerequisites`; + } + + public get taskOverseerResourcesUploadUrl(): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ this.id }/task_assessment_resources`; } - public getTaskAssessmentResourcesUrl(): string { + public getOverseerResourcesUrl(): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ this.id }/task_assessment_resources.json`; } + public get taskOverseerExecutionScriptUrl() { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${this.id}/overseer_script`; + } + + public getJplagReportUrl() { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${this.id}/jplag_report`; + } + public deleteTaskSheet(): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient.delete(this.taskSheetUploadUrl).pipe(tap(() => (this.hasTaskSheet = false))); @@ -195,13 +310,24 @@ export class TaskDefinition extends Entity { public deleteTaskResources(): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.delete(this.taskResourcesUploadUrl).pipe(tap(() => (this.hasTaskResources = false))); + return httpClient + .delete(this.taskResourcesUploadUrl) + .pipe(tap(() => (this.hasTaskResources = false))); + } + + public deleteScormData(): Observable { + const httpClient = AppInjector.get(HttpClient); + return httpClient.delete(this.scormDataUploadUrl).pipe(tap(() => (this.hasScormData = false))); } - public deleteTaskAssessmentResources(): Observable { + public deleteOverseerResources(): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient - .delete(this.taskAssessmentResourcesUploadUrl) + .delete(this.taskOverseerResourcesUploadUrl) .pipe(tap(() => (this.hasTaskAssessmentResources = false))); } + + public projectTask(project?: Project): Task | undefined { + return project?.tasks?.find((p) => p.definition.id === this.id); + } } diff --git a/src/app/api/models/task-prerequisite.ts b/src/app/api/models/task-prerequisite.ts new file mode 100644 index 0000000000..9645adfe5b --- /dev/null +++ b/src/app/api/models/task-prerequisite.ts @@ -0,0 +1,89 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskPrerequisiteService} from '../services/task-prerequisite.service'; +import {Project, TaskDefinition, TaskStatus, TaskStatusEnum} from './doubtfire-model'; + +export class TaskPrerequisite extends Entity { + id: number; + + prerequisite: TaskDefinition; + prerequisiteId: number; + taskStatusId: number; + + // Minimum required status + taskStatus: TaskStatusEnum; + + // Parent + taskDefinition: TaskDefinition; + taskDefinitionId: number; + + public readonly STATES: Partial> = { + ready_for_feedback: 1, + assess_in_portfolio: 1, + discuss: 2, + attention_required: 0, + demonstrate: 2, + complete: 3, + }; + + constructor(json: any) { + super(); + this.taskDefinitionId = json.taskDefinitionId; + this.prerequisiteId = json.prerequisiteId; + this.taskStatus = json.taskStatus; + } + + public toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + return { + task_prerequisite: super.toJson(mappingData, ignoreKeys), + }; + } + + public requiredStatusLabel() { + return TaskStatus.STATUS_LABELS.get(this.taskStatus); + } + + public hasMetRequiredState(project: Project) { + if (!this.prerequisite || !project) { + return false; + } + const prerequisiteTask = this.prerequisite.projectTask(project); + if (!prerequisiteTask) { + return false; + } + const currentStatus = prerequisiteTask.status; + const requiredStatus = this.taskStatus; + if (this.STATES[currentStatus] >= this.STATES[requiredStatus]) { + return true; + } + return false; + } + + public delete(): Observable { + const taskPrerequisiteService: TaskPrerequisiteService = + AppInjector.get(TaskPrerequisiteService); + + return taskPrerequisiteService + .delete( + { + unitId: this.taskDefinition.unit.id, + taskDefId: this.taskDefinitionId, + prerequisiteId: this.prerequisiteId, + }, + {cache: this.taskDefinition.taskPrerequisitesCache}, + ) + .pipe( + tap({ + next: () => { + AppInjector.get(AlertService).error('Successfully deleted prerequisite', 4000); + this.taskDefinition.taskPrerequisitesCache.delete(this.id); + }, + error: (error) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }), + ); + } +} diff --git a/src/app/api/models/task-similarity.ts b/src/app/api/models/task-similarity.ts index c3a72e556f..cb9640966c 100644 --- a/src/app/api/models/task-similarity.ts +++ b/src/app/api/models/task-similarity.ts @@ -1,21 +1,26 @@ -import { Entity } from 'ngx-entity-service'; -import { AppInjector } from 'src/app/app-injector'; -import { Task, TaskSimilarityService } from './doubtfire-model'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { Observable } from 'rxjs'; +import {Entity} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {Task, TaskSimilarityService, User} from './doubtfire-model'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Observable} from 'rxjs'; export enum TaskSimilarityType { + Jplag = 'JplagTaskSimilarity', Moss = 'MossTaskSimilarity', TurnItIn = 'TiiTaskSimilarity', } /** * Represents teh format for a part of a similarity report for a task. - * This is html for moss, and pdf for turn it in. + * + * HTML for moss + * PDF for TurnItIn + * jplag for JPlag */ export enum TaskSimilarityPartFormat { Html = 'html', Pdf = 'pdf', + Jplag = 'jplag', } export class TaskSimilarityPart { @@ -36,6 +41,8 @@ export class TaskSimilarity extends Entity { parts: TaskSimilarityPart[]; task: Task; readyForViewer: boolean = false; + otherTask?: Task; + otherStudent?: User; constructor(task: Task) { super(); @@ -62,6 +69,8 @@ export class TaskSimilarity extends Entity { public get friendlyTypeName(): string { switch (this.type) { + case TaskSimilarityType.Jplag: + return 'JPLAG'; case TaskSimilarityType.Moss: return 'MOSS'; case TaskSimilarityType.TurnItIn: diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 0ab0f8f2d9..0933627924 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -1,4 +1,4 @@ -import { Task } from './task'; +import {Task} from './task'; export type TaskStatusEnum = | 'not_started' @@ -12,14 +12,16 @@ export type TaskStatusEnum = | 'demonstrate' | 'complete' | 'fail' - | 'time_exceeded'; + | 'time_exceeded' + | 'assess_in_portfolio' + | 'attention_required'; export type TaskStatusUiData = { status: TaskStatusEnum; icon: string; label: string; class: string; - help: { detail: string; reason: string; action: string }; + help: {detail: string; reason: string; action: string}; }; export class TaskStatus { @@ -36,6 +38,8 @@ export class TaskStatus { 'complete', 'fail', 'time_exceeded', + 'assess_in_portfolio', + 'attention_required', ]; public static readonly VALID_TOP_TASKS: TaskStatusEnum[] = [ @@ -46,6 +50,7 @@ export class TaskStatus { 'fix_and_resubmit', 'ready_for_feedback', 'discuss', + 'attention_required', 'demonstrate', ]; @@ -57,15 +62,37 @@ export class TaskStatus { 'complete', 'fail', 'time_exceeded', + 'assess_in_portfolio', + 'attention_required', ]; - public static readonly FINAL_STATUSES: TaskStatusEnum[] = ['complete', 'fail', 'feedback_exceeded', 'time_exceeded']; + public static readonly FINAL_STATUSES: TaskStatusEnum[] = [ + 'complete', + 'fail', + 'feedback_exceeded', + 'time_exceeded', + 'assess_in_portfolio', + ]; - public static readonly GRADEABLE_STATUSES: TaskStatusEnum[] = ['fail', 'discuss', 'demonstrate', 'complete']; + public static readonly GRADEABLE_STATUSES: TaskStatusEnum[] = [ + 'fail', + 'discuss', + 'demonstrate', + 'complete', + ]; - public static readonly TO_BE_WORKED_ON: TaskStatusEnum[] = ['not_started', 'redo', 'need_help', 'working_on_it']; + public static readonly TO_BE_WORKED_ON: TaskStatusEnum[] = [ + 'not_started', + 'redo', + 'need_help', + 'working_on_it', + ]; - public static readonly DISCUSSION_STATES: TaskStatusEnum[] = ['discuss', 'demonstrate']; + public static readonly DISCUSSION_STATES: TaskStatusEnum[] = [ + 'discuss', + 'attention_required', + 'demonstrate', + ]; public static readonly STATE_THAT_ALLOWS_EXTENSION: TaskStatusEnum[] = [ 'not_started', @@ -89,7 +116,11 @@ export class TaskStatus { 'redo', ]; - public static readonly SUBMITTABLE_STATUSES: TaskStatusEnum[] = ['ready_for_feedback', 'need_help']; + public static readonly SUBMITTABLE_STATUSES: TaskStatusEnum[] = [ + 'ready_for_feedback', + 'need_help', + 'assess_in_portfolio', + ]; public static readonly MARKED_STATUSES: TaskStatusEnum[] = [ 'redo', @@ -99,9 +130,22 @@ export class TaskStatus { 'discuss', 'demonstrate', 'complete', + 'attention_required', + ]; + + public static readonly FEEDBACK_TEMPLATE_STATUSES: TaskStatusEnum[] = [ + 'complete', + 'discuss', + 'fix_and_resubmit', + 'redo', + 'feedback_exceeded', + 'attention_required', ]; - public static readonly LEARNING_WEIGHT: Map = new Map([ + public static readonly LEARNING_WEIGHT: Map = new Map< + TaskStatusEnum, + number + >([ ['fail', 0.0], ['not_started', 0.0], ['working_on_it', 0.0], @@ -114,9 +158,14 @@ export class TaskStatus { ['demonstrate', 0.8], ['complete', 1.0], ['time_exceeded', 0.3], + ['assess_in_portfolio', 1.0], + ['attention_required', 0.1], ]); - public static readonly STATUS_ACRONYM: Map = new Map([ + public static readonly STATUS_ACRONYM: Map = new Map< + TaskStatusEnum, + string + >([ ['ready_for_feedback', 'RFF'], ['not_started', 'NOS'], ['working_on_it', 'WRK'], @@ -129,6 +178,8 @@ export class TaskStatus { ['complete', 'COM'], ['fail', 'FAL'], ['time_exceeded', 'TIE'], + ['assess_in_portfolio', 'AIP'], + ['attention_required', 'AR'], ]); // Which status should not show up in the task status drop down... for students @@ -148,6 +199,8 @@ export class TaskStatus { ['feedback_exceeded', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ['time_exceeded', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ['fail', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], + ['assess_in_portfolio', ['not_started']], + ['attention_required', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ]); public static readonly STATUS_LABELS = new Map([ @@ -163,6 +216,8 @@ export class TaskStatus { ['complete', 'Complete'], ['fail', 'Fail'], ['time_exceeded', 'Time Exceeded'], + ['assess_in_portfolio', 'Assess in Portfolio'], + ['attention_required', 'Attention Required'], ]); public static readonly STATUS_ICONS = new Map([ @@ -178,6 +233,8 @@ export class TaskStatus { ['complete', 'fa fa-check'], ['fail', 'fa fa-times'], ['time_exceeded', 'fa fa-clock-o'], + ['assess_in_portfolio', 'fa fa-folder-open'], + ['attention_required', 'fa fa-commenting'], ]); // Please make sure this matches task-status-colors.less @@ -194,6 +251,8 @@ export class TaskStatus { ['complete', '#5BB75B'], ['fail', '#d93713'], ['time_exceeded', '#d93713'], + ['assess_in_portfolio', '#f2d85c'], + ['attention_required', '#f1814d'], ]); public static readonly STATUS_SEQ = new Map([ @@ -209,11 +268,23 @@ export class TaskStatus { ['discuss', 10], ['demonstrate', 11], ['complete', 12], + ['assess_in_portfolio', 13], + ['attention_required', 14], ]); public static readonly SWITCHABLE_STATES = { student: ['not_started', 'working_on_it', 'need_help', 'ready_for_feedback'], - tutor: ['complete', 'discuss', 'demonstrate', 'fix_and_resubmit', 'redo', 'feedback_exceeded', 'fail'], + tutor: [ + 'complete', + 'discuss', + 'attention_required', + 'demonstrate', + 'fix_and_resubmit', + 'redo', + 'feedback_exceeded', + 'fail', + 'assess_in_portfolio', + ], }; // detail = in a brief context to the student @@ -221,14 +292,16 @@ export class TaskStatus { // action = action student can take public static readonly HELP_DESCRIPTIONS = new Map< TaskStatusEnum, - { detail: string; reason: string; action: string } + {detail: string; reason: string; action: string} >([ [ 'ready_for_feedback', { detail: 'Submitted this task for feedback', - reason: 'You have finished working on the task and have uploaded it for your tutor to assess.', - action: 'No further action is required. Your tutor will change this task status once they have assessed it.', + reason: + 'You have finished working on the task and have uploaded it for your tutor to assess.', + action: + 'No further action is required. Your tutor will change this task status once they have assessed it.', }, ], [ @@ -252,7 +325,8 @@ export class TaskStatus { { detail: 'Need help for the task', reason: 'You are working on the task but would like some help to get it complete.', - action: 'Upload the task with what you have completed so far and add a comment on what you would like help on.', + action: + 'Upload the task with what you have completed so far and add a comment on what you would like help on.', }, ], [ @@ -269,7 +343,8 @@ export class TaskStatus { 'feedback_exceeded', { detail: 'Feedback will no longer be given', - reason: 'This work is not complete to an acceptable standard and your tutor will not reassess it again.', + reason: + 'This work is not complete to an acceptable standard and your tutor will not reassess it again.', action: "It is now your responsibility to ensure this task is at an adequate standard in your portfolio. You should fix your work according to your tutor's prior feedback and include a corrected version in your portfolio.", }, @@ -287,17 +362,28 @@ export class TaskStatus { [ 'discuss', { - detail: "You're almost complete!", - reason: 'Your work looks good and your tutor believes it is complete.', - action: 'To mark as complete, attend class and discuss it with your tutor.', + detail: 'Your work needs to be discussed further.', + reason: 'Your work looks good and your tutor believes it is on track.', + action: 'For this to be marked as complete, attend class and discuss it with your tutor.', + }, + ], + [ + 'attention_required', + { + detail: 'Your work is off track and needs focused discussion.', + reason: + 'It seems you have misunderstood some key requirements for this task. Previous feedback has not led to sufficient progress.', + action: + 'Attend class so your tutor can go through your work in detail and help you get back on track.', }, ], [ 'demonstrate', { - detail: "You're almost complete!", - reason: 'Your work looks good and your tutor believes it is complete.', - action: 'To mark as complete, attend class and demonstrate how your submission works to your tutor.', + detail: 'Your work needs to be demonstrated.', + reason: 'Your work looks good and your tutor believes it is on track.', + action: + 'For this to be marked as complete you need to attend class and demonstrate how your submission works for your tutor.', }, ], [ @@ -305,7 +391,8 @@ export class TaskStatus { { detail: 'You are finished with this task 🎉', reason: 'Your tutor is happy with your work and it has been discussed with them.', - action: 'No further action required. Move onto the next task, or go party if everything is done.', + action: + 'No further action required. Move onto the next task, or go party if everything is done.', }, ], [ @@ -321,11 +408,21 @@ export class TaskStatus { 'time_exceeded', { detail: 'Time limit exceeded', - reason: 'This work was submitted after the deadline, having missed both the target date and deadline.', + reason: + 'This work was submitted after the deadline, having missed both the target date and deadline.', action: 'Work submitted after the feedback deadline will not be checked by tutors prior to the portfolio assessment. You will need to ensure this task is at an adequate standard in your portfolio.', }, ], + [ + 'assess_in_portfolio', + { + detail: 'Your submission will be assessed in your portfolio', + reason: + 'This task will no longer be checked by tutors, and will be assessed directly in your final portfolio submission.', + action: 'You will need to ensure this task is at an adequate standard in your portfolio.', + }, + ], // [ // "awaiting_extension", // { diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 2aa167adfd..2d7d995792 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -15,6 +15,11 @@ import { TaskCommentService, TaskSimilarity, TaskSimilarityService, + TestAttempt, + TestAttemptService, + ScormComment, + UnitRoleService, + UnitRole, } from './doubtfire-model'; import {Grade} from './grade'; import {LOCALE_ID} from '@angular/core'; @@ -24,12 +29,26 @@ import {gradeTaskModal, uploadSubmissionModal} from 'src/app/ajs-upgraded-provid import {AlertService} from 'src/app/common/services/alert.service'; import {MappingFunctions} from '../services/mapping-fn'; +export const FeedbackModerationAction = { + ShowMore: 'show_more', + ShowLess: 'show_less', + DismissOk: 'dismiss_ok', + DismissGood: 'dismiss_good', + Upheld: 'upheld', + Overturn: 'overturn', + Snooze: 'snooze', +} as const; + +export type FeedbackModerationActionType = + (typeof FeedbackModerationAction)[keyof typeof FeedbackModerationAction]; + export class Task extends Entity { id: number; status: TaskStatusEnum = 'not_started'; dueDate: Date; extensions: number; + scormExtensions: number; submissionDate: Date; completionDate: Date; timesAssessed: number; @@ -40,19 +59,30 @@ export class Task extends Entity { numNewComments: number = 0; hasExtensions: boolean; + moderationType: 'random_sample' | 'escalation' | 'first_feedback'; + project: Project; definition: TaskDefinition; //TODO: map task submission details hasPdf: boolean = false; processingPdf: boolean = false; + claimedByUnitRoleId: number | null; + + loadingSubmissionDetails: boolean = false; pinned: boolean = false; + targetStartDate: Date; + targetDueDate: Date; + public topWeight: number = 0; public readonly commentCache: EntityCache = new EntityCache(); public readonly similarityCache: EntityCache = new EntityCache(); + public readonly testAttemptCache: EntityCache = new EntityCache(); + + suggestedTaskStatus; private _unit: Unit; @@ -83,6 +113,28 @@ export class Task extends Entity { return this.commentCache.currentValues; } + public get hasDiscussedInClassComment(): boolean { + return this.comments.some((comment) => comment.commentType === 'discussed_in_class'); + } + + public get requiresDiscussionForComplete(): boolean { + return !!this.definition?.requiresDiscussion; + } + + public get canMarkComplete(): boolean { + return !this.requiresDiscussionForComplete || this.hasDiscussedInClassComment; + } + + public get tutor(): UnitRole { + const enrolments = this.project.tutorialEnrolmentsCache.currentValues.filter( + (t) => t.tutorialStream.name === this.definition.tutorialStream.name, + ); + if (enrolments.length === 1) { + const user = enrolments[0].tutor; + return this.unit.staff.find((ur) => ur.user.id === user.id); + } + } + public addComment(textString): void { AppInjector.get(TaskCommentService) .addComment(this, textString, 'text') @@ -160,11 +212,29 @@ export class Task extends Entity { } public localDueDate(): Date { + if (this.unit.allowFlexibleDates) { + if (this.targetDueDate) { + // Student's custom planned date + return this.targetDueDate; + } + + // Unit target dates per grade guidelines + if (this.project.targetGrade === 1 && this.definition.cTargetDate) { + return this.definition.cTargetDate; + } + if (this.project.targetGrade === 2 && this.definition.dTargetDate) { + return this.definition.dTargetDate; + } + if (this.project.targetGrade === 3 && this.definition.hdTargetDate) { + return this.definition.hdTargetDate; + } + } + if (this.dueDate) { return this.dueDate; - } else { - return this.definition.localDueDate(); } + + return this.definition.localDueDate(); } public localDueDateString(): string { @@ -172,8 +242,80 @@ export class Task extends Entity { return formatDate(this.localDueDate(), 'd MMM', locale); } + public localDeadlineDateString(): string { + const locale: string = AppInjector.get(LOCALE_ID); + return formatDate(this.localDeadlineDate(), 'd MMM', locale); + } + + public get dueWeek(): number { + const startDate: Date = this.unit.startDate; + const dueDate: Date = this.localDueDate(); + const diffInMs: number = dueDate.getTime() - startDate.getTime(); + const diffInDays: number = Math.ceil(diffInMs / (1000 * 3600 * 24)); + + return Math.ceil(diffInDays / 7); + } + + /** + * Set the task to be due in a specific week. + * + * @returns the new due week + */ + public set dueWeek(week: number) { + // Get original due week and current due week + const tdDueWeek: number = this.definition.dueWeek; + const currentDueWeek = this.dueWeek; + + // Determine how long the extension needs to be + this.extensions = week - tdDueWeek; + + // Map to ms to adjust due date + const currentWeekDueMs = MappingFunctions.weeksMs(currentDueWeek); + const newWeekDueMs = MappingFunctions.weeksMs(week); + + // Adjust due date based on difference in current and new due weeks + this.dueDate = new Date(this.localDueDate().getTime() - currentWeekDueMs + newWeekDueMs); + } + public localDeadlineDate(): Date { - return this.definition.localDeadlineDate(); + return MappingFunctions.addDays(this.definition.localDeadlineDate(), this.project.specConDays); + } + + public savePlannedDate(): Observable { + const taskService: TaskService = AppInjector.get(TaskService); + + return taskService.update( + { + projectId: this.project.id, + taskDefId: this.definition.id, + }, + { + endpointFormat: '/projects/:projectId:/task_def_id/:taskDefId:/plan', + entity: this, + body: { + extensions: this.extensions, + }, + }, + ); + } + + public saveTargetDates(startDate: Date | string, dueDate: Date | string): Observable { + const taskService: TaskService = AppInjector.get(TaskService); + + return taskService.update( + { + projectId: this.project.id, + taskDefId: this.definition.id, + }, + { + endpointFormat: '/projects/:projectId:/task_def_id/:taskDefId:/target_dates', + entity: this, + body: { + target_start_date: startDate, + target_due_date: dueDate, + }, + }, + ); } /** @@ -236,12 +378,39 @@ export class Task extends Entity { return this.daysUntilDueDate() == 0 && !this.inSubmittedState(); } + public get startDate(): Date { + if (this.unit.allowFlexibleDates) { + if (this.targetStartDate) { + return this.targetStartDate; + } + + // Unit start dates per grade guidelines + if (this.project.targetGrade === 1 && this.definition.cStartDate) { + return this.definition.cStartDate; + } + if (this.project.targetGrade === 2 && this.definition.dStartDate) { + return this.definition.dStartDate; + } + if (this.project.targetGrade === 3 && this.definition.hdStartDate) { + return this.definition.hdStartDate; + } + } + + if (this.extensions < 0) { + // If the task has an extension, the start date is the due date minus the extension + return MappingFunctions.addWeeks(this.definition.startDate, this.extensions); + } else { + // If the task does not have an extension, the start date is the definition's start date + return this.definition.startDate; + } + } + public timeUntilStartDate(): number { - return this.timeBetween(new Date(), this.definition.startDate); + return this.timeBetween(new Date(), this.startDate); } public daysUntilStartDate() { - return this.daysBetween(new Date(), this.definition.startDate); + return this.daysBetween(new Date(), this.startDate); } public isBeforeStartDate(): boolean { @@ -275,9 +444,7 @@ export class Task extends Entity { // Always show in days, Hours, Minutes and Seconds. return `${diff} ${data.period.charAt(0).toUpperCase() + data.period.substring(1)}`; } else if (diff === 1 && data.period !== 'weeks') { - return `1 ${ - data.period.charAt(0).toUpperCase() + data.period.substring(1, data.period.length - 2) - }`; + return `1 ${data.period.charAt(0).toUpperCase() + data.period.slice(1, -1)}`; } } @@ -381,6 +548,14 @@ export class Task extends Entity { if (comments[i].replyToId) { comments[i].originalComment = comments.find((tc) => tc.id === comments[i].replyToId); } + + // Scorm series + if (comments[i].commentType === 'scorm') { + comments[i].firstInSeries = i === 0 || comments[i - 1].commentType !== 'scorm'; + (comments[i] as ScormComment).lastInScormSeries = + i + 1 === comments.length || comments[i + 1]?.commentType !== 'scorm'; + if (!comments[i].firstInSeries) comments[i].shouldShowTimestamp = false; + } } comments[comments.length - 1].shouldShowAvatar = true; @@ -396,7 +571,7 @@ export class Task extends Entity { public taskKeyToIdString(): string { const key = this.taskKey(); - return `task-key-${key.studentId}-${key.taskDefAbbr}`.replace(/[.#]/g, '-'); + return `task-key-${key.studentId}-${key.taskDefAbbr}`.replace(/[.# ]/g, '-'); } public get similaritiesDetected(): boolean { @@ -482,7 +657,7 @@ export class Task extends Entity { public getSubmissionDetails(): Observable { const http: HttpClient = AppInjector.get(HttpClient); - + this.loadingSubmissionDetails = true; return http .get( `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.project.id}/task_def_id/${ @@ -491,20 +666,50 @@ export class Task extends Entity { ) .pipe( map((response: object) => { + this.loadingSubmissionDetails = false; this.hasPdf = response['has_pdf']; this.processingPdf = response['processing_pdf']; this.submissionDate = MappingFunctions.mapDate(response, 'submission_date', this); + if (response['task_status'] && TaskStatus.STATUS_KEYS.includes(response['task_status'])) { + this.status = response['task_status']; + } + if ('claimed_by_unit_role_id' in response) { + this.claimedByUnitRoleId = response['claimed_by_unit_role_id'] as number | null; + } return this; }), ); } public get overseerEnabled(): boolean { - return ( - this.unit.overseerEnabled && - this.definition.assessmentEnabled && - this.definition.hasTaskAssessmentResources - ); + return this.unit.overseerEnabled && this.definition.assessmentEnabled; + } + + public get scormEnabled(): boolean { + return this.definition.scormEnabled && this.definition.hasScormData; + } + + public get scormPassed(): boolean { + if (this.latestCompletedTestAttempt) { + return this.latestCompletedTestAttempt.successStatus; + } + return false; + } + + /** + * Launch the SCORM player for this task in a new window. + */ + public launchScormPlayer(): void { + const url = `#/projects/${this.project.id}/task_def_id/${this.taskDefId}/scorm-player/normal`; + window.open(url, '_blank'); + } + + public get isReadyForUpload(): boolean { + return !this.scormEnabled || this.definition.scormBypassTest || this.scormPassed; + } + + public get latestCompletedTestAttempt(): TestAttempt { + return this.testAttemptCache.currentValues.find((attempt) => attempt.terminated); } public submissionUrl(asAttachment: boolean = false): string { @@ -571,7 +776,7 @@ export class Task extends Entity { } const alerts: any = AppInjector.get(AlertService); alerts.message('Submission cancelled. Status was reverted.', 6000); - } + }, ); } @@ -590,10 +795,46 @@ export class Task extends Entity { } } - public updateTaskStatus(status: TaskStatusEnum) { + public markAsDiscussed() { + const alerts: AlertService = AppInjector.get(AlertService); + const taskService: TaskService = AppInjector.get(TaskService); + + const options: RequestOptions = { + entity: this, + cache: this.project.taskCache, + body: { + discussed: true, + }, + }; + + taskService + .update( + { + projectId: this.project.id, + taskDefId: this.definition.id, + }, + options, + ) + .subscribe({ + next: (_response) => { + taskService.notifyStatusChange(this); + alerts.success('Task successfully marked as discussed in class.', 4000); + }, + error: (error) => { + alerts.error(error, 6000); + }, + }); + } + + public updateTaskStatus(status: TaskStatusEnum, markAsDiscussed?: boolean) { const oldStatus = this.status; const alerts: AlertService = AppInjector.get(AlertService); + if (status === 'complete' && !this.canMarkComplete) { + alerts.error('This task must be discussed in class before it can marked complete.', 6000); + return; + } + const updateFunc = () => { const taskService: TaskService = AppInjector.get(TaskService); const options: RequestOptions = { @@ -605,6 +846,11 @@ export class Task extends Entity { quality_pts: this.qualityPts, }, }; + + if (markAsDiscussed === true) { + options.body['discussed'] = true; + } + const hasId: boolean = this.id > 0; taskService @@ -622,6 +868,7 @@ export class Task extends Entity { this.project.taskCache.add(this); } this.processTaskStatusChange(status, alerts); + taskService.notifyStatusChange(this); }, error: (error) => { this.status = oldStatus; @@ -659,12 +906,16 @@ export class Task extends Entity { public triggerTransition(status: TaskStatusEnum): void { if (this.status === status) return; + const alerts: AlertService = AppInjector.get(AlertService); const requiresFileUpload = - ['ready_for_feedback', 'need_help'].includes(status) && this.requiresFileUpload(); + ['ready_for_feedback', 'need_help', 'assess_in_portfolio'].includes(status) && + this.requiresFileUpload(); - if (requiresFileUpload) { + if (requiresFileUpload && this.isReadyForUpload) { this.presentTaskSubmissionModal(status); + } else if (requiresFileUpload && !this.isReadyForUpload) { + alerts.error('Complete Knowledge Check first to submit files', 6000); } else { this.updateTaskStatus(status); } @@ -718,7 +969,8 @@ export class Task extends Entity { public canApplyForExtension(): boolean { return ( - this.unit.allowStudentExtensionRequests && + (this.unit.allowStudentExtensionRequests || this.unit.currentUserIsStaff) && + !this.unit.allowFlexibleDates && this.inStateThatAllowsExtension() && (!this.isPastDeadline() || this.wasSubmittedOnTime()) && this.maxWeeksCanExtend() > 0 @@ -733,9 +985,7 @@ export class Task extends Entity { } public maxWeeksCanExtend(): number { - return Math.ceil( - this.daysBetween(this.localDueDate(), this.definition.localDeadlineDate()) / 7, - ); + return Math.ceil(this.daysBetween(this.localDueDate(), this.localDeadlineDate()) / 7); } /** @@ -764,4 +1014,89 @@ export class Task extends Entity { }, ); } + + /** + * Fetch the SCORM test attempts for this task. + */ + public fetchTestAttempts(): Observable { + const testAttemptService: TestAttemptService = AppInjector.get(TestAttemptService); + return testAttemptService.query( + { + project_id: this.project.id, + task_def_id: this.taskDefId, + }, + { + cache: this.testAttemptCache, + constructorParams: this, + }, + ); + } + + public hasPrerequisiteTasks(): boolean { + if (!this.project) { + return false; + } + return this.definition.taskPrerequisitesCache.currentValues.length > 0; + } + + /** + * Returns true if this task has prerequisite tasks that are not in a submitted state + */ + public blockedByPrerequisiteTasks(): boolean { + if (!this.project) { + return false; + } + + const prereqs = this.definition.taskPrerequisitesCache.currentValues; + if (!prereqs.length) { + return false; + } + + for (const prerequisiteLink of prereqs) { + const prerequisiteTask = prerequisiteLink.prerequisite; + const task = this.project.tasks.find((t) => t.definition.id === prerequisiteTask.id); + + // If the task doesnt exist or its state has not met the minimum require state, block submission + if (!task || !prerequisiteLink.hasMetRequiredState(this.project)) { + return true; + } + } + + return false; + } + + public moderateFeedback( + action: FeedbackModerationActionType, + applyToAll: boolean = false, + ): Observable { + const unitRoleService: UnitRoleService = AppInjector.get(UnitRoleService); + + const tutor = this.tutor; + if (!tutor) { + return; + } + + return unitRoleService.post( + { + id: tutor.id, + taskId: this.id, + }, + { + endpointFormat: '/unit_roles/:id:/moderation/:taskId:', + body: { + action, + apply_to_all: applyToAll, + }, + }, + ); + } + + public requestFeedbackReview(): Observable { + const httpClient: HttpClient = AppInjector.get(HttpClient); + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${ + this.project.id + }/task_def_id/${this.definition.id}/feedback_review`; + + return httpClient.post(url, {}); + } } diff --git a/src/app/api/models/test-attempt.ts b/src/app/api/models/test-attempt.ts new file mode 100644 index 0000000000..4497028a75 --- /dev/null +++ b/src/app/api/models/test-attempt.ts @@ -0,0 +1,28 @@ +import {Entity} from 'ngx-entity-service'; +import {Task} from './doubtfire-model'; + +export class TestAttempt extends Entity { + id: number; + terminated: boolean; + completionStatus: boolean; + successStatus: boolean; + scoreScaled: number; + cmiDatamodel: string; + attemptedTime: Date; + + task: Task; + + constructor(task: Task) { + super(); + this.task = task; + } + + /** + * Open a test attempt window in review mode + */ + public review() { + const url = `#/projects/${this.task.project.id}/task_def_id/${this.task.taskDefId}/scorm-player/review/${this.id}`; + + window.open(url, '_blank'); + } +} diff --git a/src/app/api/models/tutor-note.ts b/src/app/api/models/tutor-note.ts new file mode 100644 index 0000000000..148d5fa9eb --- /dev/null +++ b/src/app/api/models/tutor-note.ts @@ -0,0 +1,55 @@ +import {Entity} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TutorNoteService} from '../services/tutor-note.service'; +import {Project, Task, TaskDefinition, UnitRole, User, UserService} from './doubtfire-model'; + +export class TutorNote extends Entity { + id: number; + + unitRole: UnitRole; + task?: Task; + taskDefinition?: TaskDefinition; + project?: Project; + user: User; + note: string; + replyTo?: TutorNote; + replyToId: number; + readByUnitRole: boolean; + + createdAt: Date; + updatedAt: Date; + + constructor(data?: UnitRole) { + super(); + if (data) { + this.unitRole = data; + } else { + console.error('Failed to get unit role'); + } + } + + public get noteIsForMe(): boolean { + const userService: UserService = AppInjector.get(UserService); + return this.unitRole.user.id === userService.currentUser.id; + } + + public get authorIsMe(): boolean { + const userService: UserService = AppInjector.get(UserService); + return this.user.id === userService.currentUser.id; + } + + public delete() { + const tutorNoteService: TutorNoteService = AppInjector.get(TutorNoteService); + tutorNoteService + .delete({unitRoleId: this.unitRole.id, id: this.id}, {cache: this.unitRole.tutorNotesCache}) + .subscribe({ + next: () => { + AppInjector.get(AlertService).error('Successfully deleted tutor note', 4000); + }, + error: (error) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/unit-role.ts b/src/app/api/models/unit-role.ts index 5868fa2f05..967d542381 100644 --- a/src/app/api/models/unit-role.ts +++ b/src/app/api/models/unit-role.ts @@ -1,16 +1,26 @@ -import { Entity, EntityMapping } from 'ngx-entity-service'; -import { User, Unit } from './doubtfire-model'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {User, Unit} from './doubtfire-model'; +import {TutorNote} from './tutor-note'; /** * A unit role represents a academic teaching role within a unit. Linking a user * to their role within the unit. */ export class UnitRole extends Entity { - id: number; role: string; user: User; unit: Unit; + observerOnly: boolean; + canMarkOverflowTasks: boolean; + mentorId: number; + tutorNoteCount: number; + + public get mentor(): UnitRole { + return this.unit?.staff.find((ur) => ur.id === this.mentorId); + } + + public readonly tutorNotesCache: EntityCache = new EntityCache(); /** * The id for updated roles - but we need to move away from this to the role string... @@ -28,10 +38,12 @@ export class UnitRole extends Entity { return this.user.matches(text) || this.unit.matches(text); } - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { unit_role: super.toJson(mappingData, ignoreKeys), - } + }; } - } diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 5c70a6eb42..e9f48f02f9 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -22,9 +22,19 @@ import { Project, TutorialStreamService, UnitRoleService, + D2lAssessmentMappingService, + OverseerImage, + OverseerImageService, } from './doubtfire-model'; import {LearningOutcome} from './learning-outcome'; import {AlertService} from 'src/app/common/services/alert.service'; +import {D2lAssessmentMapping} from './d2l/d2l_assessment_mapping'; +import {SidekiqJob} from './sidekiq-job'; +import {HttpClient, HttpParams} from '@angular/common/http'; +import {TaskPrerequisiteService} from '../services/task-prerequisite.service'; +import {MarkingSession} from './marking-session'; +import {MarkingSessionService} from '../services/marking-session.service'; +import {TaskPrerequisite} from './task-prerequisite'; export class Unit extends Entity { id: number; @@ -51,6 +61,7 @@ export class Unit extends Entity { assessmentEnabled: boolean; overseerImageId: number = null; // image needs to be lazy loadaed + private _overseerImage: OverseerImage; autoApplyExtensionBeforeDeadline: boolean; sendNotifications: boolean; @@ -60,8 +71,15 @@ export class Unit extends Entity { draftTaskDefinition: TaskDefinition; allowStudentExtensionRequests: boolean; + allowFlexibleDates: boolean = false; extensionWeeksOnResubmitRequest: number; allowStudentChangeTutorial: boolean; + markLateSubmissionsAsAssessInPortfolio: boolean; + + feedbackWarningThresholdDays: number; + feedbackOverflowThresholdDays: number; + + d2lMapping: D2lAssessmentMapping; public readonly learningOutcomesCache: EntityCache = new EntityCache(); @@ -93,6 +111,12 @@ export class Unit extends Entity { }; } + public hasChanges(): boolean { + const unitService = AppInjector.get(UnitService); + const changes = this.toJson(unitService.mapping); + return JSON.stringify(changes) !== '{"unit":{}}'; + } + public get nameAndPeriod(): string { return `${this.name} (${ this.teachingPeriod ? this.teachingPeriod.name : this.startDate.toLocaleDateString() @@ -213,6 +237,20 @@ export class Unit extends Entity { } } + /** + * Get the total duration of the unit in milliseconds. + */ + public get totalDuration(): number { + return this.endDate.valueOf() - this.startDate.valueOf(); + } + + /** + * Get the number of weeks in the unit's teaching period. + */ + public get totalWeeks(): number { + return Math.ceil(this.totalDuration / (1000 * 60 * 60 * 24 * 7)); + } + /** * Calculate how much time has elapsed in the teaching period, based on the start and * end date of the unit relative to the current date. @@ -227,12 +265,12 @@ export class Unit extends Entity { if (today >= this.endDate) return 100; const startToNow = Math.abs(today.valueOf() - this.startDate.valueOf()); - const totalDuration = Math.abs(this.endDate.valueOf() - this.startDate.valueOf()); + const totalDuration = Math.abs(this.totalDuration); return Math.round((startToNow / totalDuration) * 100); } - public rolloverTo(body: {start_date: Date; end_date: Date}): Observable; - public rolloverTo(body: {teaching_period_id: number}): Observable; + public rolloverTo(body: {new_unit_code?: string, start_date: Date; end_date: Date}): Observable; + public rolloverTo(body: {new_unit_code?: string, teaching_period_id: number}): Observable; public rolloverTo(body: any): Observable { const unitService = AppInjector.get(UnitService); @@ -370,7 +408,7 @@ export class Unit extends Entity { return alignment.taskDefinition.id === td.id; }) .sort((a: TaskOutcomeAlignment, b: TaskOutcomeAlignment) => { - return a.learningOutcome.iloNumber - b.learningOutcome.iloNumber; + return a.learningOutcome.id - b.learningOutcome.id; }); } @@ -380,6 +418,10 @@ export class Unit extends Entity { }/learning_alignments/csv.json`; } + public get gradesCSVUploadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/grades/csv`; + } + public taskStatusFactor(td: TaskDefinition): number { return 1; } @@ -388,6 +430,10 @@ export class Unit extends Entity { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/outcomes/csv`; } + public getFeedbackTemplateBatchUploadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/feedback_chips/csv`; + } + public hasStreams(): boolean { return this.tutorialStreamsCache.size > 1; } @@ -436,6 +482,15 @@ export class Unit extends Entity { return this.groupSetsCache.currentValues; } + public set overseerImage(image: OverseerImage) { + this._overseerImage = image; + this.overseerImageId = image.id; + } + + public get overseerImage(): OverseerImage { + return this._overseerImage; + } + public get overseerEnabled(): boolean { return this.assessmentEnabled && AppInjector.get(DoubtfireConstants).IsOverseerEnabled.value; // && this.overseerImageId !== null && this.overseerImageId !== undefined; } @@ -534,17 +589,160 @@ export class Unit extends Entity { return `${AppInjector.get(DoubtfireConstants).API_URL}/csv/task_definitions?unit_id=${this.id}`; } - public downloadTaskCompletionCsv(): void { - AppInjector.get(FileDownloaderService).downloadFile( - `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/task_completion.json`, - `${this.name}-task-completion.csv`, + public downloadTaskCompletionCsv(): Observable { + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/task_completion`, + ); + } + + public downloadTasksAwaitingFeedbackCsv(): Observable { + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tasks_awaiting_feedback`, + ); + } + + public downloadTaskAssessmentCountsCsv(): Observable { + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/task_assessment_counts`, + ); + } + + public downloadTutorAssessmentCsv(): Observable { + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tutor_assessments`, + ); + } + + public getUserMarkingSessions( + startDate?: Date, + endDate?: Date, + timezone?: string, + ): Observable { + let params = new HttpParams(); + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + params = params.set('timezone', timezone); + + // TODO: we should cache the data by the same start/end date + const markingSessionService = AppInjector.get(MarkingSessionService); + return markingSessionService.fetchAll( + { + unitId: this.id, + }, + {params, constructorParams: this}, + ); + } + + public downloadTutorTimesSummaryCsv( + startDate?: Date, + endDate?: Date, + timezone?: string, + ignoreSessionsDuringTutorials?: boolean, + ): Observable { + let params = new HttpParams(); + + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + params = params.set('timezone', timezone); + + params = params.set('ignore_sessions_during_tutorials', ignoreSessionsDuringTutorials ?? false); + + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tutor_times_summary`, + {params}, + ); + } + + public downloadMyTutorTimeSessionsCsv( + startDate?: Date, + endDate?: Date, + timezone?: string, + ): Observable { + let params = new HttpParams(); + + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + params = params.set('timezone', timezone); + + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/my_marking_sessions`, + {params}, + ); + } + + public hasD2lMapping(): boolean { + const doubtfireConstants = AppInjector.get(DoubtfireConstants); + return ( + doubtfireConstants.IsD2LEnabled.value && + this.d2lMapping !== undefined && + this.d2lMapping.orgUnitId !== undefined && + this.d2lMapping.orgUnitId.length > 0 ); } - public downloadTutorAssessmentCsv(): void { + public loadD2lMapping(): Observable { + const d2lMappingSvc = AppInjector.get(D2lAssessmentMappingService); + + return d2lMappingSvc.get({unitId: this.id}).pipe( + tap((mappings) => { + this.d2lMapping = mappings; + }), + ); + } + + public get staffNotesCsvDownloadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/staff_notes`; + } + + public downloadStaffNotesCsv(): void { AppInjector.get(FileDownloaderService).downloadFile( - `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tutor_assessments.json`, - `${this.name}-tutor-assessments.csv`, + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/staff_notes`, + `${this.name}-StaffNotes.csv`, ); } + + public get taskDefinitionsPrerequisitesUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/task_prerequisites`; + } + + public getTaskPrerequisites(): Observable { + const prerequisiteService = AppInjector.get(TaskPrerequisiteService); + return prerequisiteService.getUnitPrerequisites(this.id); + } } diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index 10357a1898..b11826505a 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -1,31 +1,37 @@ -import { HttpClient } from '@angular/common/http'; -import { Entity, EntityMapping } from 'ngx-entity-service'; -import { Observable, map } from 'rxjs'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { AuthenticationService } from '../doubtfire-model'; +import {HttpClient} from '@angular/common/http'; +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Observable, map} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AuthenticationService} from '../doubtfire-model'; export type Tutor = User; export class User extends Entity { - id: number; - firstName: string; - lastName: string; - optInToResearch: boolean; - studentId: string; - email: string; - username: string; - nickname: string; - systemRole: 'Admin' | 'Convenor' | 'Tutor' | 'Student' | 'Auditor'; - receiveTaskNotifications: boolean; - receivePortfolioNotifications: boolean; - receiveFeedbackNotifications: boolean; - hasRunFirstTimeSetup: boolean; - authenticationToken: string; - pronouns: string | null; - acceptedTiiEula: boolean; + public id: number; + public firstName: string; + public lastName: string; + public optInToResearch: boolean; + public studentId: string; + public email: string; + public username: string; + public nickname: string; + public systemRole: 'Admin' | 'Convenor' | 'Tutor' | 'Student' | 'Auditor'; + public receiveTaskNotifications: boolean; + public receivePortfolioNotifications: boolean; + public receiveFeedbackNotifications: boolean; + public hasRunFirstTimeSetup: boolean; + public authenticationToken: string; + public pronouns: string | null; + public acceptedTiiEula: boolean; - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + // LTI Token + public ltik: string; + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { user: super.toJson(mappingData, ignoreKeys), }; @@ -40,12 +46,22 @@ export class User extends Entity { } public get name(): string { - const fn = this.firstName.slice(0, 11); - const sn = this.lastName.slice(0, 11); - const nn = this.nickname && this.nickname.trim() ? ` (${this.nickname.trim().slice(0, 11)})` : ''; + const fn = this.firstName.slice(0, 11).trim(); + const sn = this.lastName.slice(0, 11).trim(); + const nn = + this.nickname && this.nickname.trim() ? ` (${this.nickname.trim().slice(0, 11).trim()})` : ''; return `${fn} ${sn}${nn}`; } + public get preferredName(): string { + const nickname = this.nickname?.trim(); + const firstName = this.firstName.trim(); + if (nickname) { + return nickname; + } + return firstName; + } + public matches(text: string): boolean { return ( this.studentId?.toLowerCase().indexOf(text) >= 0 || @@ -60,10 +76,12 @@ export class User extends Entity { public acceptTiiEula(): Observable { const httpClient = AppInjector.get(HttpClient); const uri = `${AppInjector.get(DoubtfireConstants).API_URL}/tii_eula/users/${this.id}/accept`; - return httpClient.put(uri, {}).pipe(map(() => { - this.acceptedTiiEula = true; - AppInjector.get(AuthenticationService).saveCurrentUser(); - return true; - })); + return httpClient.put(uri, {}).pipe( + map(() => { + this.acceptedTiiEula = true; + // AppInjector.get(AuthenticationService).saveCurrentUser(); + return true; + }), + ); } } diff --git a/src/app/api/services/activity-type.service.ts b/src/app/api/services/activity-type.service.ts index bd89cb9256..628acde622 100644 --- a/src/app/api/services/activity-type.service.ts +++ b/src/app/api/services/activity-type.service.ts @@ -1,8 +1,8 @@ -import { ActivityType } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { CachedEntityService } from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiURL'; -import { HttpClient } from '@angular/common/http'; +import {ActivityType} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; @Injectable() export class ActivityTypeService extends CachedEntityService { @@ -11,11 +11,7 @@ export class ActivityTypeService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys( - 'id', - 'name', - 'abbreviation', - ); + this.mapping.addKeys('id', 'name', 'abbreviation'); this.mapping.mapAllKeysToJsonExcept('id'); } diff --git a/src/app/api/services/authentication.service.ts b/src/app/api/services/authentication.service.ts index b2cb12f402..be59c71786 100644 --- a/src/app/api/services/authentication.service.ts +++ b/src/app/api/services/authentication.service.ts @@ -1,15 +1,45 @@ import {User, UserService} from 'src/app/api/models/doubtfire-model'; -import {Inject, Injectable} from '@angular/core'; +import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {StateService, UIRouter, UIRouterGlobals} from '@uirouter/angular'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; import {AppInjector} from 'src/app/app-injector'; -import {map, Observable} from 'rxjs'; +import {AsyncSubject, catchError, map, Observable, throwError} from 'rxjs'; import {AlertService} from 'src/app/common/services/alert.service'; +/** + * The format for the data returned from the auth api. + */ +interface AuthResponse { + user: object; + auth_token: string; + lti_token?: string; +} + @Injectable() export class AuthenticationService { + /** + * The URL for the authentication API endpoint + */ + private readonly AUTH_URL: string; + + /** + * The key used to store the username in local storage - now removed. + */ + public readonly USERNAME_KEY: string = 'doubtfire_user'; + + /** + * The key used to store the remember me option in local storage. + */ + public readonly REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN: string = + 'remember_doubtfire_credentials_token'; + + /** + * AsyncSubject to indicate when the authentication process is complete. + */ + private authComplete$: AsyncSubject = new AsyncSubject(); + constructor( private httpClient: HttpClient, private userService: UserService, @@ -20,92 +50,100 @@ export class AuthenticationService { private uiRouterGlobals: UIRouterGlobals, ) { this.AUTH_URL = `${this.doubtfireConstants.API_URL}/auth`; + // Ensure any only user data is removed from local storage + localStorage.removeItem(this.USERNAME_KEY); } - public checkUserCookie(): void { - const userData = JSON.parse(localStorage.getItem(this.USERNAME_KEY)); - const user = new User(); - Object.assign(user, userData); - - if (userData && this.tryChangeUser(user)) { - // Ensure current user is in cache - this.userService.cache.add(user); - this.userService.currentUser = user; - - const resetTime = new Date( - Number.parseInt(localStorage.getItem(this.DOUBTFIRE_LOGIN_TIME)) + 60 * 60 * 1000, - ); - const waitTime = resetTime.valueOf() - new Date().valueOf(); - - setTimeout(() => this.updateAuth(), waitTime); - } + private actionAuthFailed() { + this.signOut(false); } - private readonly AUTH_URL: string; - public readonly USERNAME_KEY: string = 'doubtfire_user'; - public readonly REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN: string = - 'remember_doubtfire_credentials_token'; - public readonly DOUBTFIRE_LOGIN_TIME: string = 'doubtfire_login_time'; - - public saveCurrentUser( - remember: boolean = localStorage.getItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN) === 'true', + /** + * Attempt to login using the refresh token secure cookie. + * This requires the remember option to be true - and the server to have sent a + * secure cookie. + * @param loginResultCallback - Callback function to indicate success or failure of login. + */ + public attemptLoginUsingRefreshToken( + loginResultCallback: (result: boolean) => void, + firstTime: boolean = true, ): void { - if (remember && this.userService.currentUser.id) { - localStorage.setItem(this.USERNAME_KEY, JSON.stringify(this.userService.currentUser)); - localStorage.setItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN, 'true'); - localStorage.setItem(this.DOUBTFIRE_LOGIN_TIME, JSON.stringify(new Date().getTime())); - } else { - localStorage.removeItem(this.USERNAME_KEY); - localStorage.setItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN, 'false'); - localStorage.removeItem(this.DOUBTFIRE_LOGIN_TIME); + // Check we have indication of secure cookie in local storage + const remember: boolean = this.rememberMe; + + if (!remember) { + loginResultCallback(false); + return; } + + // Attempt to get an access token using the refresh token cookie + this.httpClient.post(this.AUTH_URL + '/access-token', {}).subscribe({ + next: (response: AuthResponse | null) => { + if (response && response.auth_token) { + this.setupUserFromResponse(response, firstTime); + loginResultCallback(true); + } else { + this.actionAuthFailed(); + loginResultCallback(false); + } + }, + error: (_error) => { + // Will occur on 404 when the refresh token cookie is not present + this.actionAuthFailed(); + loginResultCallback(false); + }, + }); } + /** + * Check if the user is authenticated. + * + * @returns true if the user is authenticated, false otherwise. + */ public isAuthenticated(): boolean { - return this.userService.currentUser.id !== undefined; + return ( + this.userService.currentUser.id !== undefined && + !!this.userService.currentUser.authenticationToken + ); } - private updateAuth() { - if (!this.isAuthenticated()) { - return; - } + public get rememberMe(): boolean { + return localStorage.getItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN) !== 'false'; + } - const remember: boolean = - localStorage.getItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN) === 'true'; - localStorage.setItem(this.DOUBTFIRE_LOGIN_TIME, JSON.stringify(new Date().getTime())); - - this.httpClient - .put(this.AUTH_URL, { - username: this.userService.currentUser.username, - remember: remember, - }) - .subscribe({ - next: (response) => { - this.userService.currentUser.authenticationToken = response['auth_token']; - this.saveCurrentUser(remember); - - // Update auth each hour - setTimeout(() => this.updateAuth(), 1000 * 60 * 60); - }, - }); + public set rememberMe(remember: boolean) { + localStorage.setItem(this.REMEMBER_DOUBTFIRE_CREDENTIALS_TOKEN, remember ? 'true' : 'false'); } - private tryChangeUser(user: User, remember?: boolean) { - if (user) { - // Clear the current user object and populate it with the new values. - // Note how the actual user object reference doesn't change. - // delete currentUser[prop] for prop of currentUser - // _.extend currentUser, user - this.userService.currentUser = user; - this.saveCurrentUser(remember); + /** + * Get a new access token - and delete the old one. + * + * @returns void + */ + private cycleAccessToken() { + const remember: boolean = this.rememberMe; - return true; - } else { - return false; + // We cant get a new token if there is no refresh token cookie + if (!this.isAuthenticated() || !remember) { + return; } + + // Attempt to get a new access token using the refresh token cookie + this.attemptLoginUsingRefreshToken((result: boolean) => { + if (result) { + console.log('Successfully refreshed access token'); + } + }); } - private readonly validRoles: string[] = ['anon', 'Student', 'Tutor', 'Convenor', 'Admin', 'Auditor']; + private readonly validRoles: string[] = [ + 'anon', + 'Student', + 'Tutor', + 'Convenor', + 'Admin', + 'Auditor', + ]; private isValidRoleWhitelist(roleWhitelist: string[]) { return roleWhitelist.filter((role: string) => this.validRoles.includes(role)).length !== 0; @@ -123,6 +161,54 @@ export class AuthenticationService { ); } + /** + * Use the user service to get or create a user object, and update it + * from the response. Ensure that the authentication token is set. + * + * @param response the response from the authentication API + */ + private setupUserFromResponse(response: AuthResponse, firstTime: boolean = true): void { + // Extract relevant data from response and construct user object to store in cache. + const user: User = this.userService.cache.getOrCreate( + response.user['id'], + this.userService, + response.user, + ); + + // Set the user's authentication token for access to api. + user.authenticationToken = response['auth_token']; + + // Record the current user + this.userService.currentUser = user; + + if (firstTime) { + // Load everything! + AppInjector.get(GlobalStateService).loadGlobals(); + // Update token in one hour + setTimeout(() => this.cycleAccessToken(), 1000 * 60 * 60); + } + + // Inidcate that the authentication was successful + this.authComplete$.next(true); + this.authComplete$.complete(); + } + + /** + * Register a callback to be called when the authentication process is complete. + * This is used by the runtime.coffee for now to check authorisation after login + * completes. The callback will be called with true if user is authorised and if + * not will redirect to another page. + * + * @param callback the callback function to call + */ + public afterAuthCall(callback: (result: boolean) => void): void { + this.authComplete$.subscribe({ + next: (result) => { + callback(result); + }, + }); + } + public signIn( userCredentials: | { @@ -135,39 +221,56 @@ export class AuthenticationService { username: string; remember: boolean; }, - ): Observable { + ): Observable { return this.httpClient.post(this.AUTH_URL, userCredentials).pipe( - map((response: any) => { - // Extract relevant data from response and construct user object to store in cache. - const user: User = this.userService.cache.getOrCreate( - response['user']['id'], - this.userService, - response['user'], - ); - - user.authenticationToken = response['auth_token']; - - if (this.tryChangeUser(user, userCredentials.remember)) { - AppInjector.get(GlobalStateService).loadGlobals(); - } else { - return new Error('Failed to change user'); - } + map((response: AuthResponse) => { + this.setupUserFromResponse(response); + }), + catchError((error) => { + // this.authComplete$.next(false); + // this.authComplete$.complete(); + + return throwError(() => error); + }), + ); + } - // Update token in one hour - setTimeout(() => this.updateAuth(), 1000 * 60 * 60); + public signInWithLti(userCredentials: {ltik: string; lti_token: string}): Observable { + return this.httpClient.post(`${this.AUTH_URL}/lti`, userCredentials).pipe( + map((response: AuthResponse) => { + const username = encodeURIComponent(response.user['username']); + const authToken = encodeURIComponent(response.auth_token); + const ltik = encodeURIComponent(userCredentials.ltik); + setTimeout(() => { + window.location.href = `/sign_in?username=${username}&authToken=${authToken}<ik=${ltik}&isLtiLogin=true`; + }); + }), + catchError((error) => { + return throwError(() => error); }), ); } public signOut(ssoSignOut = true): void { + // This function is called after the token is deleted... const doSignOut = () => { - this.tryChangeUser(this.userService.anonymousUser, false); + // Setup ability to auth again + this.authComplete$.complete(); + this.authComplete$ = new AsyncSubject(); + + // Change the current user to the anonymous user + this.userService.currentUser = this.userService.anonymousUser; + + // Clear global state const globalStateService = AppInjector.get(GlobalStateService); + globalStateService.clearUnitsAndProjects(); + this.userService.cache.clear(); + + // Trigger the UI changes globalStateService.hideHeader(); globalStateService.setView(ViewType.OTHER); - globalStateService.clearUnitsAndProjects(); - // if string is not null + // if we have a signout URL, redirect to it if (ssoSignOut && this.doubtfireConstants.SignoutURL) { window.location.assign(this.doubtfireConstants.SignoutURL); } else { @@ -175,8 +278,9 @@ export class AuthenticationService { } }; + // If we have a token, delete it... if (this.userService.currentUser.authenticationToken) { - this.httpClient.delete(this.AUTH_URL).subscribe({ + this.httpClient.delete(this.AUTH_URL, {params: {remember: false}}).subscribe({ next: (_response) => doSignOut(), error: (_response) => doSignOut(), }); @@ -191,4 +295,12 @@ export class AuthenticationService { setTimeout(() => this.router.stateService.go('timeout'), 500); } } + + public getScormToken(): Observable { + return this.httpClient.get(this.AUTH_URL + '/scorm').pipe( + map((response) => { + return response['scorm_auth_token']; + }), + ); + } } diff --git a/src/app/api/services/campus.service.ts b/src/app/api/services/campus.service.ts index ddf491c6d4..d46d793cc3 100644 --- a/src/app/api/services/campus.service.ts +++ b/src/app/api/services/campus.service.ts @@ -1,8 +1,8 @@ -import { Campus } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { CachedEntityService } from 'ngx-entity-service'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {Campus} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class CampusService extends CachedEntityService { @@ -11,13 +11,7 @@ export class CampusService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys( - 'id', - 'name', - 'mode', - 'abbreviation', - 'active' - ); + this.mapping.addKeys('id', 'name', 'mode', 'abbreviation', 'active', 'timezone'); this.mapping.mapAllKeysToJsonExcept('id'); } diff --git a/src/app/api/services/discussion-prompt.service.ts b/src/app/api/services/discussion-prompt.service.ts new file mode 100644 index 0000000000..c102fbcbf1 --- /dev/null +++ b/src/app/api/services/discussion-prompt.service.ts @@ -0,0 +1,128 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import { + Project, + ProjectService, + TaskDefinition, + Unit, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {DiscussionPrompt} from '../models/discussion-prompt'; + +@Injectable() +export class DiscussionPromptService extends CachedEntityService { + protected readonly endpointFormat = + 'task_definitions/:task_definition_id:/discussion_prompts/:id:'; + + protected readonly projectEndpointFormat = 'projects/:projectId:/discussion_prompts'; + protected readonly taskDefinitionProjectEndpointFormat = + 'projects/:projectId:/discussion_prompts'; + protected readonly taskDefinitionEndpointFormat = + 'task_definitions/:taskDefinitionId:/discussion_prompts'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + private projectService: ProjectService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'content', + 'priority', + { + keys: ['createdBy', 'created_by_id'], + toEntityFn: (data: object, key: string, prompt: DiscussionPrompt) => { + if (prompt.project) { + return prompt.project.unit.staff.find((s) => s.user.id === data['created_by_id']).user; + } else if (prompt.taskDefinition) { + return prompt.taskDefinition.unit.staff.find((s) => s.user.id === data['created_by_id']) + ?.user; + } else if (prompt.unit) { + return prompt.unit.staff.find((s) => s.user.id === data['created_by_id'])?.user; + } + }, + }, + { + keys: ['taskDefinition', 'task_definition_id'], + toEntityFn: (data: object, key: string, entity: DiscussionPrompt) => { + if (entity.project) { + return entity.project.unit.taskDef(data[key]); + } else if (entity.unit) { + return entity.unit.taskDef(data[key]); + } + return entity.taskDefinition; + }, + toJsonFn: (entity: DiscussionPrompt, key: string) => { + return entity.taskDefinition?.id; + }, + }, + ); + + this.mapping.addJsonKey('project', 'taskDefinition', 'unit', 'createdBy'); + } + + public createInstanceFrom( + _json: object, + other?: Project | Unit | TaskDefinition, + ): DiscussionPrompt { + return new DiscussionPrompt(other); + } + + // TODO: loadDiscussionPromptsForProject and overload for loadTaskDefinitionDiscussionPrompts() + + public loadDiscussionPromptsForPoject(project: Project) { + const options: RequestOptions = { + endpointFormat: this.taskDefinitionProjectEndpointFormat, + cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project, + }; + + return super.fetchAll( + { + projectId: project?.id, + }, + options, + ); + } + + public loadDiscussionPrompts( + project: Project, + taskDefinition?: TaskDefinition, + useFetch: boolean = true, + ): Observable { + const options: RequestOptions = { + endpointFormat: project + ? taskDefinition + ? this.taskDefinitionProjectEndpointFormat + : this.projectEndpointFormat + : this.taskDefinitionEndpointFormat, + cache: taskDefinition.discussionPromptsCache, + sourceCache: taskDefinition.discussionPromptsCache, + // cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project ? project : taskDefinition, + }; + + if (useFetch) { + return super.fetchAll( + { + projectId: project?.id, + taskDefinitionId: taskDefinition?.id, + }, + options, + ); + } else { + return super.query( + { + projectId: project?.id, + taskDefinitionId: taskDefinition?.id, + }, + options, + ); + } + } +} diff --git a/src/app/api/services/feedback-template.service.ts b/src/app/api/services/feedback-template.service.ts new file mode 100644 index 0000000000..54d981d56b --- /dev/null +++ b/src/app/api/services/feedback-template.service.ts @@ -0,0 +1,35 @@ +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {FeedbackTemplate} from '../models/feedback-template'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; + +@Injectable() +export class FeedbackTemplateService extends CachedEntityService { + protected readonly endpointFormat = ':contextType:/:contextId:/feedback_chips'; + public static addEndpoint = 'feedback_chips'; + public static updateEndpoint = 'feedback_chips/:id:'; + public static globalEndpoint = 'global/feedback_chips'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'type', + 'chipText', + 'description', + 'commentText', + 'summaryText', + 'taskStatus', + 'parentChipId', + 'learningOutcomeId', + ); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public override createInstanceFrom(json: object, other?: any): FeedbackTemplate { + return new FeedbackTemplate(); + } +} diff --git a/src/app/api/services/group-set.service.ts b/src/app/api/services/group-set.service.ts index 4c976a6e4d..20fe97277e 100644 --- a/src/app/api/services/group-set.service.ts +++ b/src/app/api/services/group-set.service.ts @@ -1,8 +1,8 @@ -import { CachedEntityService } from 'ngx-entity-service'; -import { GroupSet, Unit } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {CachedEntityService} from 'ngx-entity-service'; +import {GroupSet, Unit} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class GroupSetService extends CachedEntityService { diff --git a/src/app/api/services/group.service.ts b/src/app/api/services/group.service.ts index 0c3aa086a4..c9a7435828 100644 --- a/src/app/api/services/group.service.ts +++ b/src/app/api/services/group.service.ts @@ -1,8 +1,8 @@ -import { CachedEntityService } from 'ngx-entity-service'; -import { Group, Unit } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Group, Unit} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class GroupService extends CachedEntityService { @@ -15,22 +15,22 @@ export class GroupService extends CachedEntityService { 'id', 'name', { - keys: ['groupSet','group_set_id'], + keys: ['groupSet', 'group_set_id'], toEntityFn: (data: object, jsonKey: string, grp: Group) => { return grp.unit.groupSetsCache.get(data[jsonKey]); - } + }, }, 'capacityAdjustment', 'locked', 'studentCount', { - keys: ['tutorial','tutorial_id'], + keys: ['tutorial', 'tutorial_id'], toEntityFn: (data: object, jsonKey: string, grp: Group) => { return grp.unit.tutorialsCache.get(data[jsonKey]); }, toJsonFn: (group: Group, key: string) => { return group.tutorial.id; - } + }, }, ); diff --git a/src/app/api/services/learning-outcome.service.ts b/src/app/api/services/learning-outcome.service.ts index c69ebc7224..2c4d6181c8 100644 --- a/src/app/api/services/learning-outcome.service.ts +++ b/src/app/api/services/learning-outcome.service.ts @@ -1,25 +1,30 @@ -import { CachedEntityService } from 'ngx-entity-service'; -import { LearningOutcome } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {CachedEntityService} from 'ngx-entity-service'; +import {LearningOutcome} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class LearningOutcomeService extends CachedEntityService { - protected readonly endpointFormat = 'units/:unitId:/outcomes/:id:'; + protected readonly endpointFormat = ':contextType:/:contextId:/outcomes'; + public static updateEndpoint = ':contextType:/:contextId:/outcomes/:id:'; + public static globalEndpoint = 'global/outcomes'; + public static updateGlobalEndpoint = 'global/outcomes/:id:'; constructor(httpClient: HttpClient) { super(httpClient, API_URL); this.mapping.addKeys( 'id', - 'name', - 'description', + 'contextId', + 'contextType', 'abbreviation', - 'iloNumber' + 'shortDescription', + 'fullOutcomeDescription', + 'linkedOutcomeIds', ); - this.mapping.mapAllKeysToJsonExcept('id'); + this.mapping.mapAllKeysToJsonExcept('id', 'context'); } public createInstanceFrom(json: object, other?: any): LearningOutcome { diff --git a/src/app/api/services/lti.service.ts b/src/app/api/services/lti.service.ts new file mode 100644 index 0000000000..3f97e32fda --- /dev/null +++ b/src/app/api/services/lti.service.ts @@ -0,0 +1,74 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import LTI_API_URL from 'src/app/config/constants/ltiApiUrl'; +import {Project} from '../models/project'; +import {SidekiqJob} from '../models/sidekiq-job'; + +interface info { + name?: string; + email?: string; + roles?: string[]; + custom?: any; + context?: + | { + id?: string; + label?: string; + title?: string; + type?: string[]; + } + | undefined; +} + +export interface RetrievedGrade { + id: string; + scoreOf: string; + userId: string; + resultScore: number; + resultMaximum: number; + comment: string; +} + +export interface UnitLink { + contextId?: string; + unitId: string; +} + +@Injectable() +export class LtiService { + constructor(private httpClient: HttpClient) {} + + public getInfo(): Observable { + return this.httpClient.get(`${LTI_API_URL}/info`); + } + + public getUnitLink(): Observable { + return this.httpClient.get(`${LTI_API_URL}/link`); + } + + public setUnitLink(data: UnitLink): Observable { + return this.httpClient.post(`${LTI_API_URL}/link`, data); + } + + public removeUnitLink(): Observable { + return this.httpClient.delete(`${LTI_API_URL}/link`); + } + + public enrolUser(unit: UnitLink): Observable { + return this.httpClient.post(`${LTI_API_URL}/enrol`, unit); + } + + public getMembers(): Observable { + return this.httpClient.get(`${LTI_API_URL}/members`); + } + + // Sync grades for all members in the context (course) + public syncStudentsGrades(): Observable { + return this.httpClient.post(`${LTI_API_URL}/grades`, {}); + } + + // Sync grades for all members in the context (course) + public syncEnrolments(): Observable { + return this.httpClient.post(`${LTI_API_URL}/enrolments`, {}); + } +} diff --git a/src/app/api/services/mapping-fn.ts b/src/app/api/services/mapping-fn.ts index 7302bb387f..8da53e0bb0 100644 --- a/src/app/api/services/mapping-fn.ts +++ b/src/app/api/services/mapping-fn.ts @@ -1,23 +1,34 @@ +import moment from 'moment'; + export class MappingFunctions { - public static mapDateToEndOfDay(data, key, entity, params?) { + public static mapDateToEndOfDay(data, key, _entity, _params?) { const jsonDate = new Date(data[key]); - return new Date(jsonDate.getFullYear(), jsonDate.getMonth(), jsonDate.getDate(), 23, 59, 59, 999); + return new Date( + jsonDate.getFullYear(), + jsonDate.getMonth(), + jsonDate.getDate(), + 23, // all dates map to end of day + 59, + 59, + 999, + ); } - public static mapDateToDay(data, key, entity, params?) { + public static mapDateToDay(data, key: string, _entity, _params?) { const jsonDate = new Date(data[key]); return new Date(jsonDate.getFullYear(), jsonDate.getMonth(), jsonDate.getDate()); } - public static mapDate(data, key, entity, params?) { + public static mapDate(data, key: string, _entity, _params?) { return new Date(data[key]); } public static mapDayToJson(entity: T, key: string): string { if (entity[key]) { - const month = entity[key].getMonth() + 1; - const day = entity[key].getDate(); - return `${entity[key].getFullYear()}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`; + const dateValue = moment.isMoment(entity[key]) ? entity[key].toDate() : entity[key]; + const month = dateValue.getMonth() + 1; + const day = dateValue.getDate(); + return `${dateValue.getFullYear()}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`; } else { return undefined; } @@ -50,12 +61,34 @@ export class MappingFunctions { } /** - * Calculate the time between two dates - * - * @param date1 days from this date - * @param date2 to this date - * @returns the time from date1 to date2 - */ + * Add a number of days to a date. + * + * @param date starting date + * @param days days to add + * @returns the date that is `days` days after `date` + */ + public static addDays(date: Date, days: number): Date { + return new Date(date.getTime() + MappingFunctions.dayMs(days)); + } + + /** + * Add a number of weeks to a date. + * + * @param date starting date + * @param weeks days to add + * @returns the date that is `days` days after `date` + */ + public static addWeeks(date: Date, weeks: number): Date { + return new Date(date.getTime() + MappingFunctions.weeksMs(weeks)); + } + + /** + * Calculate the time between two dates + * + * @param date1 days from this date + * @param date2 to this date + * @returns the time from date1 to date2 + */ public static timeBetween(date1: Date, date2: Date): number { return date2.getTime() - date1.getTime(); } @@ -67,7 +100,7 @@ export class MappingFunctions { * @param date2 to this date * @returns the days from date1 to date2 */ - public static daysBetween(date1: Date, date2: Date): number { + public static daysBetween(date1: Date, date2: Date): number { const diff = this.timeBetween(date1, date2); return Math.ceil(diff / (1000 * 3600 * 24)); } diff --git a/src/app/api/services/marking-session.service.ts b/src/app/api/services/marking-session.service.ts new file mode 100644 index 0000000000..a621dfa5f0 --- /dev/null +++ b/src/app/api/services/marking-session.service.ts @@ -0,0 +1,39 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Unit} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MarkingSession} from '../models/marking-session'; + +@Injectable() +export class MarkingSessionService extends CachedEntityService { + protected readonly endpointFormat = 'units/:unitId:/marking_sessions/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'startTime', + 'endTime', + 'duringTutorial', + 'durationMinutes', + + 'commentsAdded', + 'assessments', + 'submissionsOpened', + + { + keys: ['user', 'user_id'], + toEntityFn: (data: object, _key: string, markingSession: MarkingSession) => { + const userRole = markingSession.unit.staff.find((s) => s.user.id === data['user_id']); + return userRole?.user; + }, + }, + ); + } + + public createInstanceFrom(json: object, other?: Unit): MarkingSession { + return new MarkingSession(other); + } +} diff --git a/src/app/api/services/overseer-assessment.service.ts b/src/app/api/services/overseer-assessment.service.ts index 9f0017dc98..82c41e3dbc 100644 --- a/src/app/api/services/overseer-assessment.service.ts +++ b/src/app/api/services/overseer-assessment.service.ts @@ -1,16 +1,23 @@ -import { Injectable } from '@angular/core'; -import { EntityService } from 'ngx-entity-service'; -import { Observable } from 'rxjs'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { OverseerAssessment } from '../models/overseer/overseer-assessment'; +import {Injectable} from '@angular/core'; +import {EntityService} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {OverseerAssessment} from '../models/overseer/overseer-assessment'; +import {Task} from '../models/doubtfire-model'; +import {OverseerStepResultService} from './overseer-step-result.service'; @Injectable() export class OverseerAssessmentService extends EntityService { - protected readonly endpointFormat = 'projects/:project_id:/task_def_id/:td_id:/submissions/timestamps/:timestamp:'; - protected readonly triggerEndpointFormat = 'projects/:project_id:/task_def_id/:td_id:/overseer_assessment/:id:/trigger'; + protected readonly endpointFormat = + 'projects/:project_id:/task_def_id/:td_id:/submissions/timestamps/:timestamp:'; + protected readonly triggerEndpointFormat = + 'projects/:project_id:/task_def_id/:td_id:/overseer_assessment/:id:/trigger'; - constructor(httpClient: HttpClient) { + constructor( + httpClient: HttpClient, + private overseerStepResultService: OverseerStepResultService, + ) { super(httpClient, API_URL); this.mapping.addKeys( @@ -25,9 +32,28 @@ export class OverseerAssessmentService extends EntityService keys: ['timestamp', 'submission_timestamp'], toEntityFn: (data, key, entity, params?) => { return new Date(data['submission_timestamp'] * 1000); - } + }, }, - ['timestampString', 'submission_timestamp'] + ['timestampString', 'submission_timestamp'], + { + keys: 'overseerStepResults', + toEntityOp: (data: object, key: string, overseerAssesment: OverseerAssessment) => { + data[key]?.forEach((overseerStep) => { + overseerAssesment.stepResultsCache.getOrCreate( + overseerStep['id'], + this.overseerStepResultService, + overseerStep, + { + constructorParams: overseerAssesment, + }, + ); + }); + }, + }, + 'overseerStepId', + 'totalSteps', + 'passedSteps', + 'hasSubmissionFiles', ); } @@ -35,22 +61,23 @@ export class OverseerAssessmentService extends EntityService return new OverseerAssessment(other); } - public queryForTask(task: any): Observable { + public queryForTask(task: Task): Observable { const pathIds = { project_id: task.project.id, - td_id: task.definition.id + td_id: task.definition.id, }; - return this.query(pathIds, task); + return this.query(pathIds, { + constructorParams: task, + }); } - public triggerOverseer(assessment: OverseerAssessment) : Observable { + public triggerOverseer(assessment: OverseerAssessment): Observable { const pathIds = { project_id: assessment.task.project.id, td_id: assessment.task.definition.id, - id: assessment.id - } - return this.put(pathIds, { endpointFormat: this.triggerEndpointFormat }); + id: assessment.id, + }; + return this.put(pathIds, {endpointFormat: this.triggerEndpointFormat}); } - } diff --git a/src/app/api/services/overseer-image.service.ts b/src/app/api/services/overseer-image.service.ts index 53a5616f56..7edc65932f 100644 --- a/src/app/api/services/overseer-image.service.ts +++ b/src/app/api/services/overseer-image.service.ts @@ -1,9 +1,10 @@ -import { CachedEntityService } from 'ngx-entity-service'; -import { Observable, switchMap } from 'rxjs'; -import { OverseerImage } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Observable, switchMap} from 'rxjs'; +import {OverseerImage} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {SidekiqJob} from '../models/sidekiq-job'; @Injectable() export class OverseerImageService extends CachedEntityService { @@ -19,20 +20,16 @@ export class OverseerImageService extends CachedEntityService { 'tag', 'pulledImageText', 'pulledImageStatus', - 'lastPulledDate' + 'lastPulledDate', ); this.mapping.mapAllKeysToJsonExcept('id'); } - public pullDockerImage(image: OverseerImage): Observable { + public pullDockerImage(image: OverseerImage): Observable { return super.put(image, { - endpointFormat: this.pullImageEndpointFormat - }).pipe( - switchMap(response => { - return super.update(image); - }) - ) + endpointFormat: this.pullImageEndpointFormat, + }); } public createInstanceFrom(json: object, other?: any): OverseerImage { diff --git a/src/app/api/services/overseer-step-result.service.ts b/src/app/api/services/overseer-step-result.service.ts new file mode 100644 index 0000000000..f7e873281b --- /dev/null +++ b/src/app/api/services/overseer-step-result.service.ts @@ -0,0 +1,52 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {OverseerAssessment} from '../models/doubtfire-model'; +import {OverseerStepResult} from '../models/overseer/overseer-step-result'; +import {Observable} from 'rxjs'; + +@Injectable() +export class OverseerStepResultService extends CachedEntityService { + protected readonly endpointFormat = + 'units/:unitId:/task_definitions/:taskDefId:/overseer_step_results/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'overseerStepId', + 'exitStatus', + 'pass', + 'feedbackMessage', + 'stdout', + 'stdin', + 'expectedOutput', + 'stdoutSha256', + 'stdinSha256', + 'expectedOutputSha256', + ); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public createInstanceFrom(json: object, other?: any): OverseerStepResult { + return new OverseerStepResult(other as OverseerAssessment); + } + + public getOverseerStepResults(assessment: OverseerAssessment): Observable { + const pathIds = { + projectId: assessment.task.project.id, + taskDefId: assessment.task.definition.id, + id: assessment.id, + }; + + return this.query(pathIds, { + endpointFormat: + 'projects/:projectId:/task_definitions/:taskDefId:/overseer_assessments_results/:id:', + constructorParams: assessment.task, + cache: assessment.stepResultsCache, + }); + } +} diff --git a/src/app/api/services/overseer-step.service.ts b/src/app/api/services/overseer-step.service.ts new file mode 100644 index 0000000000..3d8a8fca9a --- /dev/null +++ b/src/app/api/services/overseer-step.service.ts @@ -0,0 +1,60 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {OverseerStep} from '../models/overseer/overseer-step'; +import {TaskDefinition} from '../models/task-definition'; + +@Injectable() +export class OverseerStepService extends CachedEntityService { + protected readonly endpointFormat = + 'units/:unitId:/task_definitions/:taskDefId:/overseer_steps/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + // 'taskDefinition', + 'name', + 'description', + 'displayName', + 'displayDescription', + // 'runCommand', + { + keys: 'runCommand', + toEntityFn: (data: object, key: string, entity: OverseerStep, params?: any) => { + const raw = data['run_command']; + if (raw?.startsWith('b64:')) { + entity.decodedRunCommand = atob(raw.slice(4)); + } else { + entity.decodedRunCommand = raw; + } + + return raw; + }, + }, + 'timeout', + 'sortOrder', + 'stepType', + 'partialOutputDiff', + 'stdinInputFile', + 'expectedOutputFile', + 'feedbackMessage', + 'statusOnSuccess', + 'statusOnFailure', + 'haltOnSuccess', + 'haltOnFailure', + 'showExpectedOutput', + 'showStdin', + 'showStdout', + 'enabled', + ); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public createInstanceFrom(json: object, other?: any): OverseerStep { + return new OverseerStep(other as TaskDefinition); + } +} diff --git a/src/app/api/services/project.service.ts b/src/app/api/services/project.service.ts index e9ffc791ed..fe7aaa30d0 100644 --- a/src/app/api/services/project.service.ts +++ b/src/app/api/services/project.service.ts @@ -1,14 +1,20 @@ -import { CachedEntityService, RequestOptions } from 'ngx-entity-service'; -import { CampusService, Project, Unit, UnitService, UserService } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { AppInjector } from 'src/app/app-injector'; -import { Observable } from 'rxjs'; -import { TaskService } from './task.service'; -import { MappingProcess } from 'ngx-entity-service/lib/mapping-process'; -import { TaskOutcomeAlignmentService } from './task-outcome-alignment.service'; -import { GroupService } from './group.service'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import { + CampusService, + Project, + Unit, + UnitService, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {AppInjector} from 'src/app/app-injector'; +import {Observable} from 'rxjs'; +import {TaskService} from './task.service'; +import {MappingProcess} from 'ngx-entity-service/lib/mapping-process'; +import {TaskOutcomeAlignmentService} from './task-outcome-alignment.service'; +import {GroupService} from './group.service'; @Injectable() export class ProjectService extends CachedEntityService { @@ -22,7 +28,7 @@ export class ProjectService extends CachedEntityService { private userService: UserService, private taskService: TaskService, private taskOutcomeAlignmentService: TaskOutcomeAlignmentService, - private groupService: GroupService + private groupService: GroupService, ) { super(httpClient, API_URL); @@ -33,12 +39,14 @@ export class ProjectService extends CachedEntityService { keys: ['campus', 'campus_id'], toEntityOp: (data: object, key: string, entity: Project, params?: any) => { if (data['campus_id']) { - return this.campusService.get(data['campus_id']).subscribe(campus => { entity.campus = campus; }); + return this.campusService.get(data['campus_id']).subscribe((campus) => { + entity.campus = campus; + }); } }, toJsonFn: (entity: Project, key: string) => { return entity.campus ? entity.campus.id : entity.originalJson['camput_id'] ? -1 : null; - } + }, }, { keys: 'student', @@ -46,7 +54,7 @@ export class ProjectService extends CachedEntityService { const userData = data['student']; return this.userService.cache.getOrCreate(userData.id, this.userService, userData); - } + }, }, { keys: 'userId', @@ -56,9 +64,9 @@ export class ProjectService extends CachedEntityService { this.userService.get(userId).subscribe({ next: (user) => { entity.student = user; - } + }, }); - } + }, }, 'enrolled', 'targetGrade', @@ -66,6 +74,8 @@ export class ProjectService extends CachedEntityService { 'portfolioFiles', 'compilePortfolio', 'similarityFlag', + 'specConDays', + 'staffNoteCount', { keys: 'hasPortfolio', toEntityFn: (data: object, key: string, entity: Project, params?: any) => { @@ -76,7 +86,7 @@ export class ProjectService extends CachedEntityService { else entity.portfolioStatus = 0; return result; - } + }, }, 'portfolioAvailable', 'usesDraftLearningSummary', @@ -86,29 +96,29 @@ export class ProjectService extends CachedEntityService { const values = data[key]; entity.taskStats = [ { - key: "fail", - value: Math.round((values['red_pct'] || 0) * 100) + key: 'fail', + value: Math.round((values['red_pct'] || 0) * 100), }, { - key: "not_started", + key: 'not_started', value: Math.round((values['grey_pct'] || 1) * 100), }, { - key: "working_on_it", - value: Math.round((values['orange_pct'] || 0) * 100), + key: 'working_on_it', + value: Math.round((values['orange_pct'] || 0) * 100), }, { - key: "ready_for_feedback", + key: 'ready_for_feedback', value: Math.round((values['blue_pct'] || 0) * 100), }, { - key: "complete", - value: Math.round((values['green_pct'] || 0) * 100) - } + key: 'complete', + value: Math.round((values['green_pct'] || 0) * 100), + }, ]; entity.orderScale = Math.round((values['order_scale'] || 0) * 100); - } + }, }, 'grade', 'gradeRationale', @@ -123,7 +133,7 @@ export class ProjectService extends CachedEntityService { }, toJsonFn: (entity: Project, key: string) => { return entity.unit?.id; - } + }, }, { keys: 'unitId', @@ -131,66 +141,74 @@ export class ProjectService extends CachedEntityService { const unitService: UnitService = AppInjector.get(UnitService); const unitId = process.data['unit_id']; // Load what we have... or a a stub for now... - process.entity.unit = unitService.cache.getOrCreate(unitId, unitService, { id: unitId }); - return unitService.get(unitId).subscribe(unit => { + process.entity.unit = unitService.cache.getOrCreate(unitId, unitService, {id: unitId}); + return unitService.get(unitId).subscribe((unit) => { process.entity.unit = unit; unit.studentCache.add(process.entity); process.continue(); }); - } + }, }, { keys: 'tutorialEnrolments', toEntityOp: (data: object, key: string, project: Project, params?: any) => { const unit: Unit = project.unit; - data[key].forEach((tutorialEnrolment: { tutorial_id: number; }) => { + data[key]?.forEach((tutorialEnrolment: {tutorial_id: number}) => { if (tutorialEnrolment.tutorial_id) { const tutorial = unit.tutorialsCache.get(tutorialEnrolment.tutorial_id); project.tutorialEnrolmentsCache.add(tutorial); } }); - } + }, }, { keys: 'groups', toEntityOp: (data: object, key: string, project: Project, params?: any) => { - data[key].forEach((group) => { - const theGroup = project.unit.groupSetsCache.get(group.group_set_id).groupsCache.getOrCreate(group.id, this.groupService, group, {constructorParams: project.unit}); + data[key]?.forEach((group) => { + const theGroup = project.unit.groupSetsCache + .get(group.group_set_id) + .groupsCache.getOrCreate(group.id, this.groupService, group, { + constructorParams: project.unit, + }); project.groupCache.add(theGroup); theGroup.projectsCache.add(project); - }) + }); }, toJsonFn: (entity: Project, key: string) => { return entity.unit?.id; - } + }, }, { keys: 'tasks', toEntityOp: (data: object, key: string, project: Project, params?: any) => { // create tasks from json - data['tasks'].forEach(taskData => { - project.taskCache.getOrCreate(taskData['id'], this.taskService, taskData, {constructorParams: project}); + data['tasks']?.forEach((taskData) => { + project.taskCache.getOrCreate(taskData['id'], this.taskService, taskData, { + constructorParams: project, + }); }); project.unit.setupTasksForStudent(project); - } + }, }, { keys: 'taskOutcomeAlignments', toEntityOp: (data: object, key: string, project: Project, params?: any) => { - data[key].forEach(alignment => { + data[key]?.forEach((alignment) => { project.taskOutcomeAlignmentsCache.getOrCreate( alignment['id'], taskOutcomeAlignmentService, alignment, { - constructorParams: project - } + constructorParams: project, + }, ); }); - } + }, }, + 'escalationAttemptsRemaining', + 'portfolioSubmissionDate', ); this.mapping.addJsonKey( @@ -200,7 +218,7 @@ export class ProjectService extends CachedEntityService { 'compilePortfolio', 'grade', 'gradeRationale', - 'campus' + 'campus', ); } @@ -208,16 +226,20 @@ export class ProjectService extends CachedEntityService { return new Project(other as Unit); } - public loadStudents(unit: Unit, withdrawnOnly: boolean = false, useFetch: boolean = false): Observable { + public loadStudents( + unit: Unit, + withdrawnOnly: boolean = false, + useFetch: boolean = false, + ): Observable { const options: RequestOptions = { cache: unit.studentCache, endpointFormat: this.studentEndpointFormat, params: { withdrawn: withdrawnOnly, - unit_id: unit.id + unit_id: unit.id, }, - constructorParams: unit - } + constructorParams: unit, + }; if (useFetch) { return super.fetchAll(undefined, options); @@ -226,13 +248,17 @@ export class ProjectService extends CachedEntityService { } } - public loadProject(proj: Project | number, unit: Unit, useFetch: boolean = false): Observable { + public loadProject( + proj: Project | number, + unit: Unit, + useFetch: boolean = false, + ): Observable { const options: RequestOptions = { cache: unit.studentCache, sourceCache: unit.studentCache, constructorParams: unit, - cacheBehaviourOnGet: "cacheQuery" - } + cacheBehaviourOnGet: 'cacheQuery', + }; if (useFetch) { return super.fetch(proj, options); diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts new file mode 100644 index 0000000000..bdeb14fc77 --- /dev/null +++ b/src/app/api/services/scorm-adapter.service.ts @@ -0,0 +1,283 @@ +import {Injectable} from '@angular/core'; +import {UserService} from './user.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; + +@Injectable({ + providedIn: 'root', +}) +export class ScormAdapterService { + private dataModel: ScormDataModel; + private context: ScormPlayerContext; + private xhr: XMLHttpRequest; + + constructor(private userService: UserService) { + this.dataModel = new ScormDataModel(); + this.context = new ScormPlayerContext(this.userService.currentUser); + this.xhr = new XMLHttpRequest(); + } + + set projectId(projectId: number) { + this.context.projectId = projectId; + } + + set taskDefId(taskDefId: number) { + this.context.taskDefId = taskDefId; + } + + set mode(mode: 'browse' | 'normal' | 'review' | 'preview') { + this.context.mode = mode; + } + + set testAttemptId(testAttemptId: number) { + this.context.attemptId = testAttemptId; + } + + get state() { + return this.context.state; + } + + destroy() { + this.dataModel = new ScormDataModel(); + this.context.state = 'Uninitialized'; + } + + Initialize(): string { + // console.log('API_1484_11: Initialize'); + + // TODO: error handling and reporting + switch (this.context.state) { + case 'Initialized': + this.context.errorCode = 103; + // console.log('Already Initialized'); + break; + case 'Terminated': + this.context.errorCode = 104; + // console.log('Content Instance Terminated'); + break; + } + + if (this.context.mode === 'review') { + this.xhr.open('GET', `${API_URL}/test_attempts/${this.context.attemptId}/review`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + + this.xhr.send(); + // console.log(this.xhr.responseText); + + const reviewSession = JSON.parse(this.xhr.responseText); + this.dataModel.restore(reviewSession.cmi_datamodel); + // console.log(this.dataModel.dump()); + + this.context.state = 'Initialized'; + return 'true'; + } + + // TODO: move this part into the player component + this.xhr.open( + 'GET', + `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts/latest`, + false, + ); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + + let noTestFound = false; + let startNewTest = false; + + this.xhr.onload = () => { + if (this.xhr.status == 404) { + noTestFound = true; + } + + // if (this.xhr.status >= 200 && this.xhr.status < 400) { + // console.log('Retrieved the latest attempt.'); + // } else if (this.xhr.status == 404) { + // console.log('Not found.'); + // noTestFound = true; + // } else { + // console.error('Error saving DataModel:', this.xhr.responseText); + // } + }; + + this.xhr.send(); + // console.log(this.xhr.responseText); + + if (!noTestFound) { + const latestSession = JSON.parse(this.xhr.responseText); + // console.log('Latest exam session:', latestSession); + this.context.attemptId = latestSession.id; + if (latestSession.completion_status) { + startNewTest = true; + } + } else { + startNewTest = true; + } + + if (!startNewTest) { + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + this.xhr.send(); + // console.log(this.xhr.responseText); + + const currentSession = JSON.parse(this.xhr.responseText); + // console.log('Current exam session:', currentSession); + this.context.attemptId = currentSession.id; + this.dataModel.restore(currentSession.cmi_datamodel); + // console.log(this.dataModel.dump()); + } else { + this.xhr.open( + 'POST', + `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts`, + false, + ); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + this.xhr.send(); + // console.log(this.xhr.responseText); + + const currentSession = JSON.parse(this.xhr.responseText); + // console.log('Current exam session:', currentSession); + this.context.attemptId = currentSession.id; + this.dataModel.restore(currentSession.cmi_datamodel); + // console.log(this.dataModel.dump()); + } + + this.context.state = 'Initialized'; + return 'true'; + } + + Terminate(): string { + // console.log('API_1484_11: Terminate'); + + // TODO: error handling and reporting + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 112; + // console.log('Termination Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 113; + // console.log('Termination After Termination'); + break; + } + + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + this.xhr.setRequestHeader('Content-Type', 'application/json'); + const requestData = { + cmi_datamodel: JSON.stringify(this.dataModel.dump()), + terminated: true, + }; + this.xhr.send(JSON.stringify(requestData)); + // console.log(this.xhr.responseText); + + // all done, clearing datamodel and setting state to terminated + this.dataModel = new ScormDataModel(); + this.context.state = 'Terminated'; + return 'true'; + } + + GetValue(element: string): string { + const value = this.dataModel.get(element); + + // TODO: error reporting + // TODO: can't get until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 122; + // console.log('Retrieve Data Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 123; + // console.log('Retrieve Data After Termination'); + break; + } + + // console.log(`API_1484_11: GetValue:`, element, value); + return value; + } + + SetValue(element: string, value: any): string { + // console.log(`API_1484_11: SetValue:`, element, value); + + // TODO: error reporting + // TODO: can't set until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 132; + // console.log('Store Data Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 133; + // console.log('Store Data After Termination'); + break; + } + + this.dataModel.set(element, value); + return 'true'; + } + + Commit(): string { + // console.log('API_1484_11: Commit'); + + // TODO: error reporting + // TODO: can't commit until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 142; + // console.log('Commit Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 143; + // console.log('Commit After Termination'); + break; + } + + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, true); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + this.xhr.setRequestHeader('Content-Type', 'application/json'); + const requestData = { + cmi_datamodel: JSON.stringify(this.dataModel.dump()), + }; + + // this.xhr.onload = () => { + // if (this.xhr.status >= 200 && this.xhr.status < 400) { + // console.log('DataModel saved successfully.'); + // } else { + // console.error('Error saving DataModel:', this.xhr.responseText); + // } + // }; + + // this.xhr.onerror = () => { + // console.error('Request failed.'); + // }; + + this.xhr.send(JSON.stringify(requestData)); + this.context.errorCode = 0; + return 'true'; + } + + GetLastError(): string { + const lastError = this.context.errorCode.toString(); + // if (lastError !== '0') { + // console.log(`API_1484_11: GetLastError: ${lastError}`); + // } + return lastError; + } + + GetErrorString(errorCode: string): string { + const errorString = this.context.getErrorMessage(errorCode); + // console.log(`API_1484_11: GetErrorString:`, errorCode, errorString); + return errorString; + } + + GetDiagnostic(errorCode: string): string { + // TODO: implement this + // console.log(`API_1484_11: GetDiagnostic:`, errorCode); + return 'GetDiagnostic is currently not implemented'; + } +} diff --git a/src/app/api/services/sidekiq-job.service.ts b/src/app/api/services/sidekiq-job.service.ts new file mode 100644 index 0000000000..dd5332a258 --- /dev/null +++ b/src/app/api/services/sidekiq-job.service.ts @@ -0,0 +1,100 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {BehaviorSubject, Observable, Subject} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {SidekiqJob} from '../models/sidekiq-job'; + +export interface SidekiqJobEntry { + job?: SidekiqJob; + title: string; + resultSubject: Subject; +} + +@Injectable() +export class SidekiqJobService extends CachedEntityService { + protected readonly endpointFormat = 'sidekiq/:id:'; + + public jobEntries: Map = new Map(); + + // Allow components to track changes to jobEntries + public sidekiqJobsSubject = new BehaviorSubject([]); + + public setJob(jobId: string, title: string, subject: Subject, job?: SidekiqJob) { + this.jobEntries.set(jobId, { + job, + title, + resultSubject: subject, + }); + this.emitJobs(); + } + + public removeJob(jobId: string) { + this.jobEntries.delete(jobId); + this.emitJobs(); + } + + private emitJobs() { + this.sidekiqJobsSubject.next(Array.from(this.jobEntries.values())); + } + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'jobClass', + 'status', + { + keys: 'pctComplete', + toEntityOp: (data: object, jsonKey: string, job: SidekiqJob, _params?) => { + job.pctComplete = Number(data[jsonKey]); + }, + }, + 'message', + { + keys: 'processedCount', + toEntityOp: (data: object, jsonKey: string, job: SidekiqJob, _params?) => { + job.processedCount = Number(data[jsonKey]); + }, + }, + { + keys: 'totalCount', + toEntityOp: (data: object, jsonKey: string, job: SidekiqJob, _params?) => { + job.totalCount = Number(data[jsonKey]); + }, + }, + 'result', + 'createdAt', + 'updatedAt', + ); + + this.mapping.addJsonKey( + 'id', + 'jobClass', + 'status', + 'message', + 'result', + 'createdAt', + 'updatedAt', + ); + } + + public createInstanceFrom(_json: object): SidekiqJob { + return new SidekiqJob(); + } + + public getSidekiqJob(jobId: string): Observable { + // TODO: cache the response to avoid fetching the same result data when the job is complete + return this.fetch( + { + id: jobId, + }, + { + endpointFormat: this.endpointFormat, + }, + ); + } + + // TODO: we could create endpoints to cancel/retry sidekiq jobs +} diff --git a/src/app/api/services/staff-note.service.ts b/src/app/api/services/staff-note.service.ts new file mode 100644 index 0000000000..0a707fea8c --- /dev/null +++ b/src/app/api/services/staff-note.service.ts @@ -0,0 +1,123 @@ +import {HttpClient} from '@angular/common/http'; +import {EventEmitter, Injectable} from '@angular/core'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Project, ProjectService, UserService} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {StaffNote} from '../models/staff-note'; +import {Observable, tap} from 'rxjs'; + +@Injectable() +export class StaffNoteService extends CachedEntityService { + public readonly staffNoteAdded$: EventEmitter = new EventEmitter(); + + protected readonly endpointFormat = 'projects/:projectId:/staff_notes/:id:'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + private projectService: ProjectService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys('id', 'note', 'createdAt', 'updatedAt', 'replyToId', { + keys: ['user', 'user_id'], + toEntityFn: (data: object, key: string, staffNote: StaffNote) => { + const userRole = staffNote.project.unit.staff.find((s) => s.user.id === data['user_id']); + + // const user = this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); + return userRole.user; + }, + }); + + this.mapping.addJsonKey('note', 'createdAt', 'updatedAt'); + } + + public createInstanceFrom(json: object, other?: Project): StaffNote { + return new StaffNote(other); + } + + public addNote(project: Project, text: string, originalNote: StaffNote): Observable { + const pathId = { + projectId: project.id, + }; + + const body: FormData = new FormData(); + if (originalNote) { + body.append('reply_to_id', originalNote?.id.toString()); + } + + body.append('note', text); + + const opts: RequestOptions = {endpointFormat: this.endpointFormat}; + opts.cache = project.staffNoteCache; + opts.body = body; + opts.constructorParams = project; + + return this.create(pathId, opts).pipe( + tap((note: StaffNote) => { + this.staffNoteAdded$.emit(note); + }), + ); + } + + public updateStaffNoteReplies(staffNotes: readonly StaffNote[]) { + for (const note of staffNotes) { + if (note.replyToId) { + const repliedTo = staffNotes.find((n) => n.id === note.replyToId); + if (repliedTo) { + note.replyTo = repliedTo; + } else { + // Remove deleted replies + note.replyTo = null; + } + } + } + } + + public updateNote(project: Project, note: StaffNote, text: string): Observable { + const pathId = { + projectId: project.id, + id: note.id, + }; + + const body: FormData = new FormData(); + body.append('note', text); + + const opts: RequestOptions = {endpointFormat: this.endpointFormat}; + opts.cache = project.staffNoteCache; + opts.body = body; + opts.constructorParams = project; + + return this.put(pathId, opts).pipe( + tap((_note: StaffNote) => { + note.note = text; + }), + ); + } + + public loadStaffNotes(project: Project, useFetch: boolean = false): Observable { + const options: RequestOptions = { + endpointFormat: this.endpointFormat, + cache: project.staffNoteCache, + sourceCache: project.staffNoteCache, + cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project, + }; + + if (useFetch) { + return super.fetchAll( + { + projectId: project.id, + }, + options, + ); + } else { + return super.query( + { + projectId: project.id, + }, + options, + ); + } + } +} diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 9e646be77d..6761bc715c 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -1,30 +1,44 @@ -import { Task, TaskComment, UserService } from 'src/app/api/models/doubtfire-model'; -import { EventEmitter, Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { CachedEntityService } from 'ngx-entity-service'; -import { DiscussionComment } from '../models/task-comment/discussion-comment'; -import { ExtensionComment } from '../models/task-comment/extension-comment'; -import { RequestOptions } from 'ngx-entity-service/lib/request-options'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { EmojiService } from 'src/app/common/services/emoji.service'; -import { MappingFunctions } from './mapping-fn'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; +import { + ScormComment, + Task, + TaskComment, + TestAttemptService, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {EventEmitter, Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; +import {CachedEntityService} from 'ngx-entity-service'; +import {DiscussionComment} from '../models/task-comment/discussion-comment'; +import {ExtensionComment} from '../models/task-comment/extension-comment'; +import {RequestOptions} from 'ngx-entity-service/lib/request-options'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {EmojiService} from 'src/app/common/services/emoji.service'; +import {MappingFunctions} from './mapping-fn'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {ScormExtensionComment} from '../models/task-comment/scorm-extension-comment'; @Injectable() export class TaskCommentService extends CachedEntityService { public readonly commentAdded$: EventEmitter = new EventEmitter(); - private readonly commentEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/comments/:id:'; - private readonly discussionEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/discussion_comments'; + private readonly commentEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/comments/:id:'; + private readonly discussionEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/discussion_comments'; private readonly extensionGrantEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/assess_extension/:id:'; private readonly requestExtensionEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/request_extension'; - private readonly discussionCommentReplyEndpointFormat = "/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/reply"; - private readonly getDiscussionCommentPromptEndpointFormat = "/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/prompt_number/:prompt_number:"; - + private readonly scormExtensionGrantEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/assess_scorm_extension/:id:'; + private readonly scormRequestExtensionEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/request_scorm_extension'; + private readonly discussionCommentReplyEndpointFormat = + '/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/reply'; + private readonly getDiscussionCommentPromptEndpointFormat = + '/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/prompt_number/:prompt_number:'; protected readonly endpointFormat = this.commentEndpointFormat; @@ -32,7 +46,8 @@ export class TaskCommentService extends CachedEntityService { httpClient: HttpClient, private emojiService: EmojiService, private userService: UserService, - private downloader: FileDownloaderService + private downloader: FileDownloaderService, + private testAttemptService: TestAttemptService, ) { super(httpClient, API_URL); @@ -41,16 +56,16 @@ export class TaskCommentService extends CachedEntityService { { keys: 'author', toEntityFn: (data: object, key: string, comment: TaskComment) => { - const user = this.userService.cache.getOrCreate(data[key].id, userService, data[key]); - comment.initials = `${user.firstName[0]}${user.lastName[0]}`.toUpperCase(); + const user = this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); + comment.initials = `${user.preferredName[0]}${user.lastName[0]}`.toUpperCase(); return user; - } + }, }, { keys: 'recipient', toEntityFn: (data: object, key: string, comment: TaskComment) => { - return this.userService.cache.getOrCreate(data[key].id, userService, data[key]); - } + return this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); + }, }, 'recipientReadTime', 'replyToId', @@ -59,17 +74,17 @@ export class TaskCommentService extends CachedEntityService { keys: ['text', 'comment'], toEntityFn: (data, key, entity) => { return this.emojiService.colonsToNative(data['comment']); - } + }, }, { keys: 'createdAt', - toEntityFn: MappingFunctions.mapDate + toEntityFn: MappingFunctions.mapDate, }, { keys: 'type', - toEntityOp: (data: object, key: string, comment:TaskComment) => { + toEntityOp: (data: object, key: string, comment: TaskComment) => { comment.commentType = data[key]; - } + }, }, // Extension comments 'assessed', @@ -85,13 +100,34 @@ export class TaskCommentService extends CachedEntityService { 'status', 'numberOfPrompts', 'timeDiscussionComplete', - 'timeDiscussionStarted' - ); + 'timeDiscussionStarted', - this.mapping.addJsonKey( - 'granted', + // Scorm Comments + { + keys: 'testAttempt', + toEntityFn: (data: object, key: string, comment: ScormComment) => { + const testAttempt = this.testAttemptService.cache.getOrCreate( + data[key].id, + testAttemptService, + data[key], + { + constructorParams: comment.task, + }, + ); + return testAttempt; + }, + }, + // Scorm Extension Comments + ['taskScormExtensions', 'scorm_extensions'], + 'overseerAssessmentId', + 'overseerPassedSteps', + 'overseerTotalSteps', + 'overseerInProgress', + 'overseerStatus', ); + + this.mapping.addJsonKey('granted'); } /** @@ -103,6 +139,10 @@ export class TaskCommentService extends CachedEntityService { return new DiscussionComment(other); case 'extension': return new ExtensionComment(other); + case 'scorm': + return new ScormComment(other); + case 'scorm_extension': + return new ScormExtensionComment(other); default: return new TaskComment(other); } @@ -115,13 +155,17 @@ export class TaskCommentService extends CachedEntityService { * @param other Contains the related Tasks used to construct the TaskComments * @param options */ - public query(pathIds?: object, other?: object, options?: RequestOptions): Observable { + public query( + pathIds?: object, + other?: object, + options?: RequestOptions, + ): Observable { return super.query(pathIds, options).pipe( tap((result) => { // Access the task and set the number of new comments to 0 - they are now read on the server const task = other as any; //TODO: change to Task object task.numNewComments = 0; - }) + }), ); } @@ -130,7 +174,7 @@ export class TaskCommentService extends CachedEntityService { data: string | File | Blob, commentType: string, originalComment?: TaskComment, - prompts?: Blob[] + prompts?: Blob[], ): Observable { const pathId = { projectId: task.project.id, @@ -142,10 +186,10 @@ export class TaskCommentService extends CachedEntityService { body.append('reply_to_id', originalComment?.id.toString()); } - const opts: RequestOptions = { endpointFormat: this.commentEndpointFormat }; + const opts: RequestOptions = {endpointFormat: this.commentEndpointFormat}; // Based on the comment type - add to the body and configure the end point - if (commentType === 'text') { + if (commentType === 'text' || commentType === 'scorm') { body.append('comment', data); } else if (commentType === 'discussion') { opts.endpointFormat = this.discussionEndpointFormat; @@ -164,7 +208,7 @@ export class TaskCommentService extends CachedEntityService { tap((tc: TaskComment) => { task.refreshCommentData(); this.commentAdded$.emit(tc); - }) + }), ); } @@ -180,34 +224,71 @@ export class TaskCommentService extends CachedEntityService { projectId: extension.project.id, taskDefinitionId: extension.task.definition.id, }, - opts + opts, ); } - public requestExtension(reason: string, weeksRequested: number, task: any): Observable { + public requestExtension( + reason: string, + weeksRequested: number, + task: any, + ): Observable { const opts: RequestOptions = { endpointFormat: this.requestExtensionEndpointFormat, body: { comment: reason, weeks_requested: weeksRequested, }, - cache: task.commentCache + cache: task.commentCache, + }; + return super.create( + { + projectId: task.project.id, + taskDefinitionId: task.definition.id, + }, + opts, + ); + } + + public assessScormExtension(extension: ScormExtensionComment): Observable { + const opts: RequestOptions = { + endpointFormat: this.scormExtensionGrantEndpointFormat, + entity: extension, + }; + + return super.update( + { + id: extension.id, + projectId: extension.project.id, + taskDefinitionId: extension.task.definition.id, + }, + opts, + ); + } + + public requestScormExtension(reason: string, task: any): Observable { + const opts: RequestOptions = { + endpointFormat: this.scormRequestExtensionEndpointFormat, + body: { + comment: reason, + }, + cache: task.commentCache, }; return super.create( { projectId: task.project.id, taskDefinitionId: task.definition.id, }, - opts + opts, ); } - public postDiscussionReply(comment: TaskComment, replyAudio: Blob): Observable{ + public postDiscussionReply(comment: TaskComment, replyAudio: Blob): Observable { const form = new FormData(); const pathIds = { project_id: comment.project.id, task_definition_id: comment.task.id, - task_comment_id: comment.id + task_comment_id: comment.id, }; form.append('attachment', replyAudio); diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 13a1dd2797..d420f2c1fc 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -1,17 +1,32 @@ -import { CachedEntityService } from 'ngx-entity-service'; -import { TaskDefinition, Unit } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { MappingFunctions } from './mapping-fn'; -import { AppInjector } from 'src/app/app-injector'; -import { Observable } from 'rxjs'; +import {CachedEntityService} from 'ngx-entity-service'; +import { + LearningOutcomeService, + TaskDefinition, + TaskStatusEnum, + Unit, +} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MappingFunctions} from './mapping-fn'; +import {AppInjector} from 'src/app/app-injector'; +import {Observable} from 'rxjs'; +import {TaskPrerequisiteService} from './task-prerequisite.service'; +import {TaskPrerequisite} from '../models/task-prerequisite'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {SidekiqJob} from '../models/sidekiq-job'; +import {OverseerStepService} from './overseer-step.service'; @Injectable() export class TaskDefinitionService extends CachedEntityService { protected readonly endpointFormat = 'units/:unitId:/task_definitions/:id:'; - constructor(httpClient: HttpClient) { + constructor( + httpClient: HttpClient, + private learningOutcomeService: LearningOutcomeService, + private taskPrerequisiteService: TaskPrerequisiteService, + private overseerStepService: OverseerStepService, + ) { super(httpClient, API_URL); this.mapping.addKeys( @@ -21,7 +36,10 @@ export class TaskDefinitionService extends CachedEntityService { 'description', 'weighting', 'targetGrade', - 'mossLanguage', + 'similarityLanguage', + 'hasJplagReport', + 'assessInPortfolioOnly', + 'requiresDiscussion', { keys: 'targetDate', toEntityFn: MappingFunctions.mapDateToEndOfDay, @@ -41,7 +59,7 @@ export class TaskDefinitionService extends CachedEntityService { keys: 'uploadRequirements', toJsonFn: (taskDef: TaskDefinition, key: string) => { return JSON.stringify( - taskDef.uploadRequirements.map((upreq) => { + taskDef.uploadRequirements?.map((upreq) => { return { key: upreq.key, name: upreq.name, @@ -49,13 +67,19 @@ export class TaskDefinitionService extends CachedEntityService { tii_check: upreq.tiiCheck, tii_pct: upreq.tiiPct, }; - }) + }), ); }, toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { return ( - data[key] as Array<{ key: string; name: string; type: string; tii_check: boolean; tii_pct: number }> - ).map((upreq) => { + data[key] as Array<{ + key: string; + name: string; + type: string; + tii_check: boolean; + tii_pct: number; + }> + )?.map((upreq) => { return { key: upreq.key, name: upreq.name, @@ -93,17 +117,92 @@ export class TaskDefinitionService extends CachedEntityService { 'hasTaskSheet', 'hasTaskResources', 'hasTaskAssessmentResources', + 'hasTaskAssessmentScript', + 'scormEnabled', + 'hasScormData', + 'scormAllowReview', + 'scormBypassTest', + 'scormTimeDelayEnabled', + 'scormAttemptLimit', 'isGraded', 'maxQualityPts', 'overseerImageId', - 'assessmentEnabled' + 'assessmentEnabled', + 'discussionPromptsCount', + { + keys: 'ilos', + toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { + data[key]?.forEach((ilo) => { + taskDefinition.learningOutcomesCache.getOrCreate( + ilo['id'], + this.learningOutcomeService, + ilo, + ); + }); + }, + }, + 'useResourcesForJplagBaseCode', + 'lockAssessmentsToTutorialStream', + { + keys: 'overseerSteps', + toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { + data[key]?.forEach((overseerStep) => { + taskDefinition.overseerStepsCache.getOrCreate( + overseerStep['id'], + this.overseerStepService, + overseerStep, + { + constructorParams: taskDefinition, + }, + ); + }); + }, + }, + 'overseerResourceFiles', + // { + // keys: 'pTargetDate', + // toEntityFn: MappingFunctions.mapDateToDay, + // toJsonFn: MappingFunctions.mapDayToJson, + // }, + { + keys: 'cTargetDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, + { + keys: 'dTargetDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, + { + keys: 'hdTargetDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, + + { + keys: 'cStartDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, + { + keys: 'dStartDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, + { + keys: 'hdStartDate', + toEntityFn: MappingFunctions.mapDateToDay, + toJsonFn: MappingFunctions.mapDayToJson, + }, ); this.mapping.mapAllKeysToJsonExcept( 'id', 'hasTaskSheet', 'hasTaskResources', - 'hasTaskAssessmentResources' + 'hasTaskAssessmentResources', + 'hasScormData', ); } @@ -120,12 +219,58 @@ export class TaskDefinitionService extends CachedEntityService { public uploadTaskResources(taskDefinition: TaskDefinition, file: File): Observable { const formData = new FormData(); formData.append('file', file); - return AppInjector.get(HttpClient).post(taskDefinition.taskResourcesUploadUrl, formData); + return AppInjector.get(HttpClient).post( + taskDefinition.taskResourcesUploadUrl, + formData, + ); } - public uploadOverseerResources(taskDefinition: TaskDefinition, file: File): Observable { + public uploadOverseerResources(taskDefinition: TaskDefinition, file: File): Observable { const formData = new FormData(); formData.append('file', file); - return AppInjector.get(HttpClient).post(taskDefinition.taskAssessmentResourcesUploadUrl, formData); + return AppInjector.get(HttpClient).post( + taskDefinition.taskOverseerResourcesUploadUrl, + formData, + ); + } + + public uploadScormData(taskDefinition: TaskDefinition, file: File): Observable { + const formData = new FormData(); + formData.append('file', file); + return AppInjector.get(HttpClient).post(taskDefinition.scormDataUploadUrl, formData); + } + + public addTaskPrerequisite( + taskDefinition: TaskDefinition, + prerequsite: TaskDefinition, + ): Observable { + return AppInjector.get(HttpClient).post(taskDefinition.taskPrerequisiteUrl, { + task_def_id: taskDefinition.id, + prerequisite_id: prerequsite.id, + }); + } + + public updateTaskPrerequisite( + taskPrerequisiteLink: TaskPrerequisite, + taskStatus: TaskStatusEnum, + ): Observable { + return AppInjector.get(HttpClient).put( + `${taskPrerequisiteLink.taskDefinition.taskPrerequisiteUrl}/${taskPrerequisiteLink.id}`, + { + task_status_required: taskStatus, + }, + ); + } + + public zipSubmissionFiles(taskDefinition: TaskDefinition): Observable { + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/submission/units/${taskDefinition.unit.id}/task_definitions/${taskDefinition.id}/download_submissions/zip`; + const httpClient = AppInjector.get(HttpClient); + return httpClient.get(url); + } + + public zipSubmissionPdfs(taskDefinition: TaskDefinition): Observable { + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/submission/units/${taskDefinition.unit.id}/task_definitions/${taskDefinition.id}/student_pdfs/zip`; + const httpClient = AppInjector.get(HttpClient); + return httpClient.get(url); } } diff --git a/src/app/api/services/task-outcome-alignment.service.ts b/src/app/api/services/task-outcome-alignment.service.ts index 061f14a91e..44fd1ea07f 100644 --- a/src/app/api/services/task-outcome-alignment.service.ts +++ b/src/app/api/services/task-outcome-alignment.service.ts @@ -1,9 +1,9 @@ -import { HttpClient } from '@angular/common/http'; -import { CachedEntityService } from 'ngx-entity-service'; -import { Project, TaskOutcomeAlignment, Unit } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import API_URL from 'src/app/config/constants/apiURL'; -import { UnitTutorialsListComponent } from 'src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component'; +import {HttpClient} from '@angular/common/http'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Project, TaskOutcomeAlignment, Unit} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {UnitTutorialsListComponent} from 'src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component'; @Injectable() export class TaskOutcomeAlignmentService extends CachedEntityService { @@ -24,7 +24,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { return entity.learningOutcome.id; - } + }, }, { keys: ['taskDefinition', 'task_definition_id'], @@ -34,7 +34,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { return entity.taskDefinition.id; - } + }, }, { keys: ['task', 'task_id'], @@ -44,14 +44,14 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { return entity.task?.id; - } - } + }, + }, ); this.mapping.mapAllKeysToJsonExcept('id'); } public override createInstanceFrom(json: any, other?: any): TaskOutcomeAlignment { - return new TaskOutcomeAlignment(other as (Unit | Project)); + return new TaskOutcomeAlignment(other as Unit | Project); } } diff --git a/src/app/api/services/task-prerequisite.service.ts b/src/app/api/services/task-prerequisite.service.ts new file mode 100644 index 0000000000..ffb323b0d1 --- /dev/null +++ b/src/app/api/services/task-prerequisite.service.ts @@ -0,0 +1,37 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {TaskPrerequisite} from '../models/task-prerequisite'; + +@Injectable() +export class TaskPrerequisiteService extends CachedEntityService { + protected readonly endpointFormat = + 'units/:unitId:/task_definitions/:taskDefId:/prerequisites/:prerequisiteId:'; + + protected readonly unitEndpointFormat = 'units/:unitId:/task_prerequisites'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys('id', 'taskDefinitionId', 'prerequisiteId', 'taskStatus'); + + // this.mapping.mapAllKeysToJsonExcept('id', 'taskDefinitionId', 'prerequisiteId', 'taskStatus'); + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public override createInstanceFrom(json: object, other?: any): TaskPrerequisite { + return new TaskPrerequisite(json); + } + + public getUnitPrerequisites(unitId: number) { + return this.fetchAll( + { + unitId: unitId, + }, + { + endpointFormat: this.unitEndpointFormat, + }, + ); + } +} diff --git a/src/app/api/services/task-similarity.service.ts b/src/app/api/services/task-similarity.service.ts index d2770d8009..2dafa21d23 100644 --- a/src/app/api/services/task-similarity.service.ts +++ b/src/app/api/services/task-similarity.service.ts @@ -1,11 +1,11 @@ -import { Task, TaskSimilarity } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { CachedEntityService } from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiURL'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {Task, TaskSimilarity} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @Injectable() export class TaskSimilarityService extends CachedEntityService { @@ -14,7 +14,16 @@ export class TaskSimilarityService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys('id', 'type', 'flagged', 'pct', 'readyForViewer', 'parts'); + this.mapping.addKeys( + 'id', + 'type', + 'flagged', + 'pct', + 'readyForViewer', + 'parts', + 'otherTask', + 'otherStudent', + ); this.mapping.addJsonKey('flagged'); } @@ -26,6 +35,8 @@ export class TaskSimilarityService extends CachedEntityService { public getSimilarityReportUrl(taskId: number, similarityId: number): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.get(`${AppInjector.get(DoubtfireConstants).API_URL}/tasks/${taskId}/similarities/${similarityId}/viewer_url`); + return httpClient.get( + `${AppInjector.get(DoubtfireConstants).API_URL}/tasks/${taskId}/similarities/${similarityId}/viewer_url`, + ); } } diff --git a/src/app/api/services/task.service.ts b/src/app/api/services/task.service.ts index 344494c0eb..8aaa3805a2 100644 --- a/src/app/api/services/task.service.ts +++ b/src/app/api/services/task.service.ts @@ -7,19 +7,23 @@ import { TaskStatusUiData, Unit, } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import { CachedEntityService, EntityCache, RequestOptions } from 'ngx-entity-service'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { MappingFunctions } from './mapping-fn'; -import { Observable, map, tap } from 'rxjs'; +import {EventEmitter, Injectable} from '@angular/core'; +import {CachedEntityService, EntityCache, RequestOptions} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MappingFunctions} from './mapping-fn'; +import {Observable, map, tap} from 'rxjs'; @Injectable() export class TaskService extends CachedEntityService { + public readonly taskStatusUpdated$: EventEmitter = new EventEmitter(); + protected readonly endpointFormat = '/projects/:projectId:/task_def_id/:taskDefId:'; private readonly taskInboxEndpoint = '/units/:id:/tasks/inbox'; private readonly taskExplorerEndpoint = '/units/:id:/task_definitions/:task_def_id:/tasks'; + private readonly taskModerationEndpoint = '/units/:id:/tasks/moderation'; + private readonly taskOverflowEndpoint = '/units/:id:/tasks/overflow'; private readonly refreshTaskEndpoint = 'projects/:projectId:/refresh_tasks/:taskDefinitionId:'; constructor(httpClient: HttpClient) { @@ -45,10 +49,19 @@ export class TaskService extends CachedEntityService { keys: 'dueDate', toEntityFn: MappingFunctions.mapDateToEndOfDay, }, + { + keys: 'targetStartDate', + toEntityFn: MappingFunctions.mapDateToEndOfDay, + }, + { + keys: 'targetDueDate', + toEntityFn: MappingFunctions.mapDateToEndOfDay, + }, 'extensions', + 'scormExtensions', { keys: 'submissionDate', - toEntityFn: MappingFunctions.mapDateToDay, + toEntityFn: MappingFunctions.mapDate, }, { keys: 'completionDate', @@ -85,7 +98,8 @@ export class TaskService extends CachedEntityService { } }); }, - } + }, + 'moderationType', ); this.mapping.addJsonKey('qualityPts', 'grade', 'includeInPortfolio', 'trigger'); @@ -95,7 +109,11 @@ export class TaskService extends CachedEntityService { return new Task(other as Project); } - public queryTasksForTaskInbox(unit: Unit, taskDef?: TaskDefinition | number): Observable { + public queryTasksForTaskInbox( + unit: Unit, + taskDef?: TaskDefinition | number, + fetchMyStudentsOnly?: boolean, + ): Observable { const cache: EntityCache = new EntityCache(); return this.query( @@ -106,15 +124,21 @@ export class TaskService extends CachedEntityService { endpointFormat: this.taskInboxEndpoint, cache: cache, constructorParams: unit, - } + params: { + my_students_only: fetchMyStudentsOnly, + }, + }, ).pipe( tap((tasks: Task[]) => { unit.incorporateTasks(tasks); - }) + }), ); } - public queryTasksForTaskExplorer(unit: Unit, taskDef?: TaskDefinition | number): Observable { + public queryTasksForTaskExplorer( + unit: Unit, + taskDef?: TaskDefinition | number, + ): Observable { const cache: EntityCache = new EntityCache(); return this.query( { @@ -125,12 +149,48 @@ export class TaskService extends CachedEntityService { endpointFormat: this.taskExplorerEndpoint, cache: cache, constructorParams: unit, - } + }, ).pipe( map((tasks: Task[]) => { unit.incorporateTasks(tasks); return unit.fillWithUnStartedTasks(tasks, taskDef); - }) + }), + ); + } + + public queryTasksForMentorModeration(unit: Unit): Observable { + const cache: EntityCache = new EntityCache(); + return this.query( + { + id: unit.id, + }, + { + endpointFormat: this.taskModerationEndpoint, + cache: cache, + constructorParams: unit, + }, + ).pipe( + tap((tasks: Task[]) => { + unit.incorporateTasks(tasks); + }), + ); + } + + public queryTasksForOverflow(unit: Unit): Observable { + const cache: EntityCache = new EntityCache(); + return this.query( + { + id: unit.id, + }, + { + endpointFormat: this.taskOverflowEndpoint, + cache: cache, + constructorParams: unit, + }, + ).pipe( + tap((tasks: Task[]) => { + unit.incorporateTasks(tasks); + }), ); } @@ -159,6 +219,7 @@ export class TaskService extends CachedEntityService { public readonly stateThatAllowsExtension = TaskStatus.STATE_THAT_ALLOWS_EXTENSION; public readonly pdfRegeneratableStatuses = TaskStatus.PDF_REGENERATABLE_STATES; public readonly submittableStatuses = TaskStatus.SUBMITTABLE_STATUSES; + public readonly feedbackTemplateStatuses = TaskStatus.FEEDBACK_TEMPLATE_STATUSES; public readonly completeStatus: TaskStatusEnum = 'complete'; public readonly learningWeight: Map = TaskStatus.LEARNING_WEIGHT; public readonly statusAcronym: Map = TaskStatus.STATUS_ACRONYM; @@ -173,6 +234,10 @@ export class TaskService extends CachedEntityService { return TaskStatus.statusClass(status); } + public notifyStatusChange(task: Task): void { + this.taskStatusUpdated$.emit(task); + } + public readonly statusColors: Map = TaskStatus.STATUS_COLORS; public readonly switchableStates = TaskStatus.SWITCHABLE_STATES; @@ -180,7 +245,7 @@ export class TaskService extends CachedEntityService { return TaskStatus.STATUS_LABELS.get(status); } - public helpDescription(status: TaskStatusEnum): { detail: string; reason: string; action: string } { + public helpDescription(status: TaskStatusEnum): {detail: string; reason: string; action: string} { return TaskStatus.HELP_DESCRIPTIONS.get(status); } @@ -188,7 +253,7 @@ export class TaskService extends CachedEntityService { return TaskStatus.statusData(data); } - public taskKeyFromString(taskKeyString: string): { studentId: string; taskDefAbbr: string } { + public taskKeyFromString(taskKeyString: string): {studentId: string; taskDefAbbr: string} { const taskKeyComponents = taskKeyString?.split('/'); if (taskKeyComponents) { const studentId = taskKeyComponents[0]; @@ -201,4 +266,36 @@ export class TaskService extends CachedEntityService { return null; } + + public checkInTaskForStudent(task: Task): Observable { + const options: RequestOptions = { + entity: task, + cache: task.project.taskCache, + endpointFormat: `${this.endpointFormat}/check_in`, + }; + + return this.post( + { + projectId: task.project.id, + taskDefId: task.definition.id, + }, + options, + ); + } + + public claimTask(task: Task): Observable { + const options: RequestOptions = { + entity: task, + cache: task.project.taskCache, + endpointFormat: `${this.endpointFormat}/claim_overflow_task`, + }; + + return this.post( + { + projectId: task.project.id, + taskDefId: task.definition.id, + }, + options, + ); + } } diff --git a/src/app/api/services/teaching-period-break.service.ts b/src/app/api/services/teaching-period-break.service.ts index 0dd023264f..a7e3b296de 100644 --- a/src/app/api/services/teaching-period-break.service.ts +++ b/src/app/api/services/teaching-period-break.service.ts @@ -1,9 +1,9 @@ -import { HttpClient } from '@angular/common/http'; -import { CachedEntityService } from 'ngx-entity-service'; -import { TeachingPeriodBreak } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import API_URL from 'src/app/config/constants/apiURL'; -import { MappingFunctions } from './mapping-fn'; +import {HttpClient} from '@angular/common/http'; +import {CachedEntityService} from 'ngx-entity-service'; +import {TeachingPeriodBreak} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MappingFunctions} from './mapping-fn'; @Injectable() export class TeachingPeriodBreakService extends CachedEntityService { @@ -17,7 +17,7 @@ export class TeachingPeriodBreakService extends CachedEntityService { @@ -12,7 +16,10 @@ export class TeachingPeriodService extends CachedEntityService { public static readonly rolloverEndpointFormat = 'teaching_periods/:id:/rollover'; - constructor(httpClient: HttpClient, private teachingPeriodBreakService: TeachingPeriodBreakService) { + constructor( + httpClient: HttpClient, + private teachingPeriodBreakService: TeachingPeriodBreakService, + ) { super(httpClient, API_URL); this.mapping.addKeys( diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts new file mode 100644 index 0000000000..9b418045ec --- /dev/null +++ b/src/app/api/services/test-attempt.service.ts @@ -0,0 +1,88 @@ +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {Task, TestAttempt} from 'src/app/api/models/doubtfire-model'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {HttpClient} from '@angular/common/http'; + +@Injectable() +export class TestAttemptService extends CachedEntityService { + protected readonly endpointFormat = + 'projects/:project_id:/task_def_id/:task_def_id:/test_attempts'; + protected readonly latestCompletedEndpoint = + this.endpointFormat + '/latest?completed=:completed:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'terminated', + 'completionStatus', + 'successStatus', + 'scoreScaled', + 'cmiDatamodel', + 'attemptedTime', + ); + } + + public override createInstanceFrom(_json: object, constructorParams: Task): TestAttempt { + return new TestAttempt(constructorParams); + } + + public getLatestCompletedAttempt(task: Task): Observable { + return this.get( + { + project_id: task.project.id, + task_def_id: task.taskDefId, + completed: true, + }, + { + endpointFormat: this.latestCompletedEndpoint, + constructorParams: task, + }, + ); + } + + public overrideSuccessStatus(testAttemptId: number, successStatus: boolean): void { + const http = AppInjector.get(HttpClient); + + http + .patch( + `${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/${testAttemptId}?success_status=${successStatus}`, + {}, + ) + .subscribe({ + next: (_data) => { + (AppInjector.get(AlertService) as AlertService).success( + 'Attempt pass status successfully overridden.', + 6000, + ); + }, + error: (message) => { + (AppInjector.get(AlertService) as AlertService).error(message, 6000); + }, + }); + } + + public deleteAttempt(testAttemptId: number): void { + const http = AppInjector.get(HttpClient); + + http + .delete(`${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/${testAttemptId}`, {}) + .subscribe({ + next: (_data) => { + (AppInjector.get(AlertService) as AlertService).success( + 'Attempt successfully deleted.', + 6000, + ); + }, + error: (message) => { + (AppInjector.get(AlertService) as AlertService).error(message, 6000); + }, + }); + } +} diff --git a/src/app/api/services/tii-action.service.ts b/src/app/api/services/tii-action.service.ts index a90e540142..d4bbc813ce 100644 --- a/src/app/api/services/tii-action.service.ts +++ b/src/app/api/services/tii-action.service.ts @@ -1,11 +1,11 @@ -import { HttpClient } from '@angular/common/http'; -import { CachedEntityService, Entity } from 'ngx-entity-service'; -import { TiiAction, Unit, UnitService, UserService } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import API_URL from 'src/app/config/constants/apiURL'; -import { AppInjector } from 'src/app/app-injector'; -import { MappingFunctions } from './mapping-fn'; -import { MappingProcess } from 'ngx-entity-service/lib/mapping-process'; +import {HttpClient} from '@angular/common/http'; +import {CachedEntityService, Entity} from 'ngx-entity-service'; +import {TiiAction, Unit, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {AppInjector} from 'src/app/app-injector'; +import {MappingFunctions} from './mapping-fn'; +import {MappingProcess} from 'ngx-entity-service/lib/mapping-process'; @Injectable() export class TiiActionService extends CachedEntityService { @@ -30,7 +30,7 @@ export class TiiActionService extends CachedEntityService { }, 'errorCode', 'errorMessage', - 'log' + 'log', ); this.mapping.addJsonKey('id', 'retry'); diff --git a/src/app/api/services/tii.service.ts b/src/app/api/services/tii.service.ts index cfc02681a3..385e9eef5c 100644 --- a/src/app/api/services/tii.service.ts +++ b/src/app/api/services/tii.service.ts @@ -1,7 +1,7 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import API_URL from 'src/app/config/constants/apiURL'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable({ providedIn: 'root', diff --git a/src/app/api/services/tutor-note.service.ts b/src/app/api/services/tutor-note.service.ts new file mode 100644 index 0000000000..3e08ce451d --- /dev/null +++ b/src/app/api/services/tutor-note.service.ts @@ -0,0 +1,176 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {ProjectService, Task, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {TutorNote} from '../models/tutor-note'; + +@Injectable() +export class TutorNoteService extends CachedEntityService { + protected readonly endpointFormat = 'unit_roles/:unitRoleId:/tutor_notes/:id:'; + protected readonly markAsReadEndpointFormat = + 'unit_roles/:unitRoleId:/tutor_notes/:id:/mark_as_read'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + private projectService: ProjectService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'note', + 'createdAt', + 'updatedAt', + 'replyToId', + { + keys: ['user', 'user_id'], + toEntityFn: (data: object, _key: string, tutorNote: TutorNote) => { + const userRole = tutorNote.unitRole.unit.staff.find((s) => s.user.id === data['user_id']); + // If the user is not a staff in the unit it will be null + return userRole?.user; + }, + }, + { + keys: ['taskDefinition', 'task_definition_id'], + toEntityFn: (data: object, _key: string, tutorNote: TutorNote) => { + const taskDefinition = tutorNote.unitRole.unit.taskDefinitions.find( + (td) => td.id === data['task_definition_id'], + ); + return taskDefinition; + }, + }, + { + keys: ['project', 'project_id'], + toEntityFn: (data: object, key: string, tutorNote: TutorNote) => { + const project = tutorNote.unitRole.unit.students.find((p) => p.id === data['project_id']); + return project; + }, + }, + 'readByUnitRole', + ); + + this.mapping.addJsonKey('note', 'createdAt', 'updatedAt'); + } + + public createInstanceFrom(_json: object, other?: UnitRole): TutorNote { + return new TutorNote(other); + } + + public addNote( + unitRole: UnitRole, + text: string, + task?: Task, + originalNote?: TutorNote, + ): Observable { + const pathId = { + unitRoleId: unitRole.id, + }; + + const body: FormData = new FormData(); + if (originalNote) { + body.append('reply_to_id', originalNote?.id.toString()); + } + + if (task) { + body.append('task_id', task?.id.toString()); + } + + body.append('note', text); + + const opts: RequestOptions = {endpointFormat: this.endpointFormat}; + opts.cache = unitRole.tutorNotesCache; + opts.body = body; + opts.constructorParams = unitRole; + + return this.create(pathId, opts); + } + + public updateTutorNoteReplies(tutorNotes: readonly TutorNote[]) { + for (const note of tutorNotes) { + if (note.replyToId) { + const repliedTo = tutorNotes.find((n) => n.id === note.replyToId); + if (repliedTo) { + note.replyTo = repliedTo; + } else { + // Remove deleted replies + note.replyTo = null; + } + } + } + } + + public updateNote(unitRole: UnitRole, note: TutorNote, text: string): Observable { + const pathId = { + unitRoleId: unitRole.id, + id: note.id, + }; + + const body: FormData = new FormData(); + body.append('note', text); + + const opts: RequestOptions = {endpointFormat: this.endpointFormat}; + opts.cache = unitRole.tutorNotesCache; + opts.body = body; + opts.constructorParams = unitRole; + + return this.put(pathId, opts).pipe( + tap((_note: TutorNote) => { + note.note = text; + }), + ); + } + + public markAsRead(unitRole: UnitRole, note: TutorNote): Observable { + const pathId = { + unitRoleId: unitRole.id, + id: note.id, + }; + + const opts: RequestOptions = {endpointFormat: this.markAsReadEndpointFormat}; + opts.cache = unitRole.tutorNotesCache; + opts.constructorParams = unitRole; + + return this.put(pathId, opts).pipe( + tap((response: boolean) => { + if (response) { + note.readByUnitRole = true; + if (unitRole.user.id !== note.user.id) { + unitRole.tutorNoteCount--; + } + // unitRole.tutorNoteCount = unitRole.tutorNotesCache.currentValues.filter( + // (note) => !note.readByUnitRole, + // ).length; + } + }), + ); + } + + public loadTutorNotes(unitRole: UnitRole, useFetch: boolean = false): Observable { + const options: RequestOptions = { + endpointFormat: this.endpointFormat, + cache: unitRole.tutorNotesCache, + sourceCache: unitRole.tutorNotesCache, + cacheBehaviourOnGet: 'cacheQuery', + constructorParams: unitRole, + }; + + if (useFetch) { + return super.fetchAll( + { + unitRoleId: unitRole.id, + }, + options, + ); + } else { + return super.query( + { + unitRoleId: unitRole.id, + }, + options, + ); + } + } +} diff --git a/src/app/api/services/tutorial-stream.service.ts b/src/app/api/services/tutorial-stream.service.ts index 648e84d4fa..4a5c5a617d 100644 --- a/src/app/api/services/tutorial-stream.service.ts +++ b/src/app/api/services/tutorial-stream.service.ts @@ -1,8 +1,8 @@ -import { HttpClient } from '@angular/common/http'; -import { CachedEntityService } from 'ngx-entity-service'; -import { TutorialStream } from 'src/app/api/models/doubtfire-model'; -import { Injectable } from '@angular/core'; -import API_URL from 'src/app/config/constants/apiURL'; +import {HttpClient} from '@angular/common/http'; +import {CachedEntityService} from 'ngx-entity-service'; +import {TutorialStream} from 'src/app/api/models/doubtfire-model'; +import {Injectable} from '@angular/core'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class TutorialStreamService extends CachedEntityService { @@ -11,11 +11,7 @@ export class TutorialStreamService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys( - 'name', - 'abbreviation', - 'activityType' - ); + this.mapping.addKeys('name', 'abbreviation', 'activityType'); this.mapping.mapAllKeysToJson(); } diff --git a/src/app/api/services/tutorial.service.ts b/src/app/api/services/tutorial.service.ts index 179ad8031a..02cb6cc746 100644 --- a/src/app/api/services/tutorial.service.ts +++ b/src/app/api/services/tutorial.service.ts @@ -1,16 +1,23 @@ -import { Inject, Injectable } from '@angular/core'; -import { analyticsService } from 'src/app/ajs-upgraded-providers'; -import { HttpClient } from '@angular/common/http'; -import { CampusService, Project, Tutorial, Unit, UserService } from 'src/app/api/models/doubtfire-model'; -import { CachedEntityService, RequestOptions } from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiURL'; -import { Observable } from 'rxjs'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Inject, Injectable} from '@angular/core'; +import {analyticsService} from 'src/app/ajs-upgraded-providers'; +import {HttpClient} from '@angular/common/http'; +import { + CampusService, + Project, + Tutorial, + Unit, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {Observable} from 'rxjs'; +import {AlertService} from 'src/app/common/services/alert.service'; @Injectable() export class TutorialService extends CachedEntityService { protected readonly endpointFormat = 'tutorials/:id:'; - protected readonly switchTutorialEndpointFormat = 'units/:unitId:/tutorials/:tutorialAbbreviation:/enrolments/:projectId:'; + protected readonly switchTutorialEndpointFormat = + 'units/:unitId:/tutorials/:tutorialAbbreviation:/enrolments/:projectId:'; constructor( httpClient: HttpClient, @@ -28,7 +35,7 @@ export class TutorialService extends CachedEntityService { 'meetingLocation', 'abbreviation', { - keys: ['campus','campus_id'], + keys: ['campus', 'campus_id'], toEntityOp: (data: object, key: string, entity: Tutorial, params?: any) => { this.campusService.get(data['campus_id']).subscribe((campus) => { entity.campus = campus; @@ -36,7 +43,7 @@ export class TutorialService extends CachedEntityService { }, toJsonFn: (entity: Tutorial, key: string) => { return entity.campus ? entity.campus.id : -1; - } + }, }, 'capacity', { @@ -46,26 +53,26 @@ export class TutorialService extends CachedEntityService { }, toJsonFn: (entity: Tutorial, key: string) => { return entity.tutor?.id; - } + }, }, 'numStudents', { - keys: ['tutorialStream','tutorial_stream_abbr'], + keys: ['tutorialStream', 'tutorial_stream_abbr'], toEntityFn: (data: object, key: string, entity: Tutorial, params?: any) => { return entity.unit.tutorialStreamForAbbr(data[key]); }, toJsonFn: (entity: Tutorial, key: string) => { return entity.tutorialStream ? entity.tutorialStream.abbreviation : null; - } + }, }, { keys: ['unit', 'unit_id'], toJsonFn: (entity: Tutorial, key: string) => { return entity.unit?.id; - } - } + }, + }, ); this.mapping.mapAllKeysToJsonExcept('numStudents'); @@ -94,7 +101,7 @@ export class TutorialService extends CachedEntityService { endpointFormat: this.switchTutorialEndpointFormat, cache: project.tutorialEnrolmentsCache, sourceCache: project.unit.tutorialsCache, - body: {} + body: {}, }; var observer: Observable; @@ -110,7 +117,9 @@ export class TutorialService extends CachedEntityService { if (isEnrol) { project.tutorialEnrolmentsCache.clear(); for (const enrolment of value.enrolments) { - project.tutorialEnrolmentsCache.add(project.unit.tutorialFromId(enrolment['tutorial_id'])); + project.tutorialEnrolmentsCache.add( + project.unit.tutorialFromId(enrolment['tutorial_id']), + ); } } else { project.tutorialEnrolmentsCache.delete(tutorial); @@ -118,8 +127,7 @@ export class TutorialService extends CachedEntityService { }, error: (error) => { this.alerts.error(`Failed to update tutorial enrolment. ${error}`, 8000); - } + }, }); } - } diff --git a/src/app/api/services/unit-role.service.ts b/src/app/api/services/unit-role.service.ts index a65f301ca8..b67a40d41c 100644 --- a/src/app/api/services/unit-role.service.ts +++ b/src/app/api/services/unit-role.service.ts @@ -1,9 +1,15 @@ -import { TeachingPeriodService, Unit, UnitRole, UnitService, UserService } from 'src/app/api/models/doubtfire-model'; -import { CachedEntityService } from 'ngx-entity-service'; -import { Inject, Injectable } from '@angular/core'; -import { analyticsService } from 'src/app/ajs-upgraded-providers'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import { + TeachingPeriodService, + Unit, + UnitRole, + UnitService, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Inject, Injectable} from '@angular/core'; +import {analyticsService} from 'src/app/ajs-upgraded-providers'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class UnitRoleService extends CachedEntityService { @@ -14,7 +20,7 @@ export class UnitRoleService extends CachedEntityService { private userService: UserService, private unitService: UnitService, private teachingPeriodService: TeachingPeriodService, - @Inject(analyticsService) private AnalyticsService: any + @Inject(analyticsService) private AnalyticsService: any, ) { super(httpClient, API_URL); @@ -34,7 +40,7 @@ export class UnitRoleService extends CachedEntityService { }, toJsonFn: (entity: UnitRole, key: string) => { return entity.unit?.id; - } + }, }, { keys: 'user', @@ -48,21 +54,32 @@ export class UnitRoleService extends CachedEntityService { keys: 'userId', toJsonFn: (entity: UnitRole, key: string) => { return entity.user?.id; - } + }, }, { keys: 'unitId', toJsonFn: (entity: UnitRole, key: string) => { return entity.unit?.id; - } + }, }, + 'observerOnly', + 'mentorId', + 'tutorNoteCount', + 'canMarkOverflowTasks', ); - this.mapping.addJsonKey('roleId', 'userId', 'unitId', 'role'); + this.mapping.addJsonKey( + 'roleId', + 'userId', + 'unitId', + 'role', + 'observerOnly', + 'mentorId', + 'canMarkOverflowTasks', + ); } public createInstanceFrom(json: any, other?: any): UnitRole { return new UnitRole(); } - } diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 740e9b6cc1..1d6462727d 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -1,14 +1,25 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { GroupSetService, LearningOutcomeService, TaskOutcomeAlignmentService, TeachingPeriodService, TutorialService, TutorialStreamService, Unit, UserService } from 'src/app/api/models/doubtfire-model'; -import { CachedEntityService, Entity, EntityMapping } from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiURL'; -import { UnitRoleService } from './unit-role.service'; -import { AppInjector } from 'src/app/app-injector'; -import { TaskDefinitionService } from './task-definition.service'; -import { GroupService } from './group.service'; -import { Observable } from 'rxjs'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import { + GroupSetService, + LearningOutcomeService, + OverseerImageService, + TaskOutcomeAlignmentService, + TeachingPeriodService, + TutorialService, + TutorialStreamService, + Unit, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {CachedEntityService, Entity, EntityMapping} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {UnitRoleService} from './unit-role.service'; +import {AppInjector} from 'src/app/app-injector'; +import {TaskDefinitionService} from './task-definition.service'; +import {GroupService} from './group.service'; +import {Observable} from 'rxjs'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; export type IloStats = { median: number; @@ -32,7 +43,7 @@ export class UnitService extends CachedEntityService { private taskDefinitionService: TaskDefinitionService, private taskOutcomeAlignmentService: TaskOutcomeAlignmentService, private groupSetService: GroupSetService, - private groupService: GroupService + private groupService: GroupService, ) { super(httpClient, API_URL); @@ -50,7 +61,7 @@ export class UnitService extends CachedEntityService { toEntityFn: (data: object, jsonKey: string, entity: Unit) => { const unitRoleService = AppInjector.get(UnitRoleService); unitRoleService.cache.get(data[jsonKey]); - } + }, }, { keys: 'staff', @@ -58,19 +69,21 @@ export class UnitService extends CachedEntityService { const unitRoleService = AppInjector.get(UnitRoleService); // Add staff entity.staffCache.clear(); - data[key].forEach(staff => { + data[key]?.forEach((staff) => { entity.staffCache.add(unitRoleService.buildInstance(staff)); }); - } + }, }, { keys: ['mainConvenor', 'main_convenor_id'], toEntityFn: (data, key, entity) => { - return entity.staffCache.get(data[key]); + let result = entity.staffCache.get(data[key]); + entity.mainConvenorUser = result?.user; + return result; }, toJsonFn: (unit: Unit, key: string) => { return unit.mainConvenor?.id; - } + }, }, { keys: ['mainConvenorUser', 'main_convenor_user_id'], @@ -79,20 +92,22 @@ export class UnitService extends CachedEntityService { }, toJsonFn: (unit: Unit, key: string) => { return unit.mainConvenor?.user.id; - } + }, }, { keys: ['teachingPeriod', 'teaching_period_id'], toEntityFn: (data, key, entity) => { - if ( data['teaching_period_id'] ) { + if (data['teaching_period_id']) { const teachingPeriod = this.teachingPeriodService.cache.get(data['teaching_period_id']); teachingPeriod?.unitsCache.add(entity); return teachingPeriod; - } else { return undefined; } + } else { + return undefined; + } }, toJsonFn: (entity: Unit, key: string) => { return entity.teachingPeriod ? entity.teachingPeriod.id : undefined; - } + }, }, { keys: 'startDate', @@ -101,7 +116,7 @@ export class UnitService extends CachedEntityService { }, toJsonFn: (entity, key) => { return entity.startDate.toISOString().slice(0, 10); - } + }, }, { keys: 'endDate', @@ -110,7 +125,7 @@ export class UnitService extends CachedEntityService { }, toJsonFn: (entity, key) => { return entity.endDate.toISOString().slice(0, 10); - } + }, }, { keys: 'portfolioAutoGenerationDate', @@ -119,70 +134,101 @@ export class UnitService extends CachedEntityService { }, toJsonFn: (entity, key) => { return entity.portfolioAutoGenerationDate?.toISOString().slice(0, 10); - } + }, }, 'assessmentEnabled', - 'overseerImageId', + // 'overseerImageId', + { + keys: 'overseerImageId', + toEntityFn: (data, key, entity) => { + const overSeerEntityId = data[key]; + if (overSeerEntityId) { + const overseerImageService = AppInjector.get(OverseerImageService); + overseerImageService.get(data[key]).subscribe({ + next: (image) => { + entity.overseerImage = image; + }, + }); + } + return overSeerEntityId; + }, + toJsonFn: (unit: Unit, _key: string) => { + return unit.overseerImage?.id; + }, + }, 'autoApplyExtensionBeforeDeadline', 'sendNotifications', 'enableSyncEnrolments', 'enableSyncTimetable', 'allowStudentExtensionRequests', + 'allowFlexibleDates', 'extensionWeeksOnResubmitRequest', 'allowStudentChangeTutorial', + 'markLateSubmissionsAsAssessInPortfolio', { keys: 'ilos', toEntityOp: (data: object, key: string, unit: Unit) => { - data[key].forEach(ilo => { + data[key]?.forEach((ilo) => { unit.learningOutcomesCache.getOrCreate(ilo['id'], this.learningOutcomeService, ilo); }); - } + }, }, { keys: 'tutorialStreams', toEntityOp: (data, key, entity) => { data['tutorial_streams'].forEach((streamJson: object) => { - entity.tutorialStreamsCache.add(this.tutorialStreamService.buildInstance(streamJson, {constructorParams: entity})); + entity.tutorialStreamsCache.add( + this.tutorialStreamService.buildInstance(streamJson, {constructorParams: entity}), + ); }); - } + }, }, { keys: 'tutorials', toEntityOp: (data, key, entity) => { data['tutorials'].forEach((tutorialJson: object) => { if (tutorialJson) { - entity.tutorialsCache.add(this.tutorialService.buildInstance(tutorialJson, {constructorParams: entity})); + entity.tutorialsCache.add( + this.tutorialService.buildInstance(tutorialJson, {constructorParams: entity}), + ); } }); - } + }, }, // 'tutorialEnrolments', - map to tutorial enrolments { keys: 'groupSets', toEntityOp: (data, key, unit) => { - data[key].forEach((groupSetJson: object) => { - unit.groupSetsCache.add(this.groupSetService.buildInstance(groupSetJson, {constructorParams: unit})); + data[key]?.forEach((groupSetJson: object) => { + unit.groupSetsCache.add( + this.groupSetService.buildInstance(groupSetJson, {constructorParams: unit}), + ); }); - } + }, }, { keys: 'groups', toEntityOp: (data, key, unit) => { - data[key].forEach((groupJson: object) => { + data[key]?.forEach((groupJson: object) => { const group = this.groupService.buildInstance(groupJson, {constructorParams: unit}); group.groupSet.groupsCache.add(group); }); - } + }, }, { keys: 'taskDefinitions', toEntityOp: (data, key, unit) => { var seq: number = 0; data['task_definitions'].forEach((taskDefinitionJson: object) => { - const td = unit.taskDefinitionCache.getOrCreate(taskDefinitionJson['id'], this.taskDefinitionService, taskDefinitionJson, {constructorParams: unit}); + const td = unit.taskDefinitionCache.getOrCreate( + taskDefinitionJson['id'], + this.taskDefinitionService, + taskDefinitionJson, + {constructorParams: unit}, + ); td.seq = seq++; }); - } + }, }, { keys: ['draftTaskDefinition', 'draft_task_definition_id'], @@ -191,24 +237,26 @@ export class UnitService extends CachedEntityService { }, toJsonFn: (unit: Unit, key: string) => { return unit.draftTaskDefinition?.id; - } + }, }, { keys: 'taskOutcomeAlignments', toEntityOp: (data: object, jsonKey: string, unit: Unit) => { - data[jsonKey].forEach( (alignment) => { + data[jsonKey].forEach((alignment) => { unit.taskOutcomeAlignmentsCache.getOrCreate( alignment['id'], this.taskOutcomeAlignmentService, alignment, { - constructorParams: unit - } + constructorParams: unit, + }, ); }); - } + }, }, // 'groupMemberships', - map to group memberships + 'feedbackWarningThresholdDays', + 'feedbackOverflowThresholdDays', ); this.mapping.addJsonKey( @@ -225,17 +273,21 @@ export class UnitService extends CachedEntityService { 'portfolioAutoGenerationDate', 'assessmentEnabled', - // 'overseerImage', - map to overseer image + 'overseerImageId', 'autoApplyExtensionBeforeDeadline', + 'markLateSubmissionsAsAssessInPortfolio', 'sendNotifications', 'enableSyncEnrolments', 'enableSyncTimetable', 'draftTaskDefinition', + 'allowFlexibleDates', 'allowStudentExtensionRequests', 'extensionWeeksOnResubmitRequest', - 'allowStudentChangeTutorial' + 'allowStudentChangeTutorial', + 'feedbackWarningThresholdDays', + 'feedbackOverflowThresholdDays', ); } @@ -277,4 +329,11 @@ export class UnitService extends CachedEntityService { return httpClient.get(url); } + + public zipPortfolios(unit: Unit): Observable { + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/submission/units/${unit.id}/portfolio/zip`; + const httpClient = AppInjector.get(HttpClient); + + return httpClient.get(url); + } } diff --git a/src/app/api/services/user.service.ts b/src/app/api/services/user.service.ts index 3473607c02..d4396e8666 100644 --- a/src/app/api/services/user.service.ts +++ b/src/app/api/services/user.service.ts @@ -1,11 +1,11 @@ -import { UnitRole, UnitService, User } from 'src/app/api/models/doubtfire-model'; -import { CachedEntityService, RequestOptions } from 'ngx-entity-service'; -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; -import { AppInjector } from 'src/app/app-injector'; -import { AuthenticationService } from './authentication.service'; -import { Observable, tap } from 'rxjs'; +import {UnitRole, UnitService, User} from 'src/app/api/models/doubtfire-model'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {AppInjector} from 'src/app/app-injector'; +import {AuthenticationService} from './authentication.service'; +import {Observable, tap} from 'rxjs'; @Injectable() export class UserService extends CachedEntityService { @@ -34,7 +34,7 @@ export class UserService extends CachedEntityService { 'receiveFeedbackNotifications', 'hasRunFirstTimeSetup', 'pronouns', - 'acceptedTiiEula' + 'acceptedTiiEula', ); this._currentUser = this.anonymousUser; @@ -72,19 +72,8 @@ export class UserService extends CachedEntityService { this._currentUser = user; } - // Specific to the User entity - public override update(pathIds: object | User, options?: RequestOptions): Observable { - return super.update(pathIds, options).pipe( - tap((user) => { - if (user === this.currentUser) { - AppInjector.get(AuthenticationService).saveCurrentUser(); - } - }) - ); - } - public getTutors(): Observable { - return this.query(undefined, { endpointFormat: this.tutorEndpointFormat }); + return this.query(undefined, {endpointFormat: this.tutorEndpointFormat}); } public adminRoleFor(unitId: number, user: User): UnitRole { @@ -97,7 +86,7 @@ export class UserService extends CachedEntityService { result.user = user; const unitService = AppInjector.get(UnitService); - result.unit = unitService.cache.getOrCreate(unitId, unitService, { id: unitId }); + result.unit = unitService.cache.getOrCreate(unitId, unitService, {id: unitId}); return result; } diff --git a/src/app/api/services/webcal.service.ts b/src/app/api/services/webcal.service.ts index 0823ff7360..9644b85d73 100644 --- a/src/app/api/services/webcal.service.ts +++ b/src/app/api/services/webcal.service.ts @@ -1,8 +1,8 @@ -import { Injectable } from '@angular/core'; -import { Webcal } from '../models/webcal/webcal'; -import { Entity, EntityService } from 'ngx-entity-service'; -import { HttpClient } from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiURL'; +import {Injectable} from '@angular/core'; +import {Webcal} from '../models/webcal/webcal'; +import {Entity, EntityService} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class WebcalService extends EntityService { @@ -23,7 +23,7 @@ export class WebcalService extends EntityService { // Only used when updating the webcal. 'shouldChangeGuid', - 'reminder' + 'reminder', ); this.mapping.mapAllKeysToJsonExcept('id'); diff --git a/src/app/common/archive-viewer/archive-viewer.component.html b/src/app/common/archive-viewer/archive-viewer.component.html new file mode 100644 index 0000000000..da1de5293f --- /dev/null +++ b/src/app/common/archive-viewer/archive-viewer.component.html @@ -0,0 +1,193 @@ +
+ @if (isLoading) { +
+ + Loading archive... +
+ } @else if (errorMessage) { +
+ error_outline + {{ errorMessage }} +
+ } @else if (!archiveFile) { +
+ folder_zip + Select an archive to preview. +
+ } @else if (!hasFiles) { +
+ folder_off + No files to display. +
+ } @else { + @if (!readOnly && saveEndpoint) { +
+ +
+ } + + @if (navigationMode === 'tree') { +
+ +
+ +
+
+ } @else { +
+
+ + @for (file of files; track trackByPath($index, file); let i = $index) { + + {{ file.tabLabel }} + + } + +
+
+ + } + } +
+ + + @if (selectedFile; as file) { +
+ @if (showPreview) { + @if (file.isLoading || !file.isLoaded) { +
+ + Loading {{ file.name }}... +
+ } @else if (isArchiveCodeOrTextFile(file)) { +
+ + +
+ } @else if (isArchiveImageFile(file)) { +
+ +
+ +
+
+ } @else if (isArchivePdfFile(file)) { +
+ + +
+ } @else { +
+ insert_drive_file +
+

This file type cannot be previewed.

+ +
+
+ } + } +
+ } +
+ + + @for (node of nodes; track trackTreeNode($index, node)) { + @if (node.isDirectory) { +
+ folder + {{ node.name }} +
+ + } @else { + + } + } +
+ + +
+ {{ path }} +
+
diff --git a/src/app/common/archive-viewer/archive-viewer.component.scss b/src/app/common/archive-viewer/archive-viewer.component.scss new file mode 100644 index 0000000000..62defd6df8 --- /dev/null +++ b/src/app/common/archive-viewer/archive-viewer.component.scss @@ -0,0 +1,34 @@ +:host { + display: block; + min-width: 0; + width: 100%; + height: 100%; + min-height: 0; +} + +.archive-editor-wrapper, +.archive-pdf-wrapper { + width: 100%; + height: 100%; + min-height: 350px; + flex: 1 1 auto; + overflow: hidden; +} + +:host ::ng-deep .archive-monaco { + width: 100% !important; + height: 100% !important; +} + +:host ::ng-deep .archive-monaco .monaco-editor, +:host ::ng-deep .archive-monaco .overflow-guard, +:host ::ng-deep .archive-monaco .monaco-scrollable-element { + width: 100% !important; + height: 100% !important; +} + +.small-icon { + width: 12px; + height: 12px; + font-size: 12px; +} diff --git a/src/app/common/archive-viewer/archive-viewer.component.ts b/src/app/common/archive-viewer/archive-viewer.component.ts new file mode 100644 index 0000000000..152f261b25 --- /dev/null +++ b/src/app/common/archive-viewer/archive-viewer.component.ts @@ -0,0 +1,464 @@ +import {HttpClient, HttpResponse} from '@angular/common/http'; +import { + Component, + EventEmitter, + Input, + OnChanges, + OnDestroy, + Output, + SimpleChanges, +} from '@angular/core'; +import JSZip from 'jszip'; +import {firstValueFrom} from 'rxjs'; +import {AlertService} from '../services/alert.service'; +import { + ArchiveFileEntry, + classifyArchiveFile, + createArchiveFileEntry, + createArchiveFilePlaceholder, + getMonacoLanguageForPath, + getOrderedUploadFileIndex, + isArchiveCodeOrTextFile, + isArchiveImageFile, + isArchivePathHidden, + isArchivePdfFile, +} from './archive-viewer.helpers'; + +type ArchiveViewerNavigationMode = 'tabs' | 'tree'; + +interface ArchiveFileTreeNode { + key: string; + name: string; + path: string; + isDirectory: boolean; + fileIndex: number | null; + children: ArchiveFileTreeNode[]; +} + +@Component({ + selector: 'f-archive-viewer', + templateUrl: './archive-viewer.component.html', + styleUrls: ['./archive-viewer.component.scss'], +}) +export class ArchiveViewerComponent implements OnChanges, OnDestroy { + @Input() archiveFile: File | Blob | null = null; + @Input() navigationMode: ArchiveViewerNavigationMode = 'tabs'; + @Input() readOnly = true; + @Input() uploadRequirementNames: string[] = []; + @Input() showPreview = true; + @Input() preloadSelectedFile = false; + @Input() saveEndpoint?: string; + @Input() saveMethod: 'POST' | 'PUT' = 'POST'; + @Input() saveFieldName = 'file'; + @Input() saveFileName = 'archive.zip'; + + @Output() filesLoaded = new EventEmitter(); + @Output() saveSuccess = new EventEmitter>(); + @Output() saveError = new EventEmitter(); + @Output() selectedFileChanged = new EventEmitter(); + + public files: ArchiveFileEntry[] = []; + public selectedTab = 0; + public isLoading = false; + public isSaving = false; + public errorMessage: string | null = null; + public fileTreeNodes: ArchiveFileTreeNode[] = []; + + public readonly isArchiveCodeOrTextFile = isArchiveCodeOrTextFile; + public readonly isArchiveImageFile = isArchiveImageFile; + public readonly isArchivePdfFile = isArchivePdfFile; + + public readonly editorOptions = { + theme: 'vs', + language: 'plaintext', + automaticLayout: true, + scrollBeyondLastLine: false, + renderMinimap: false, + scrollbar: { + alwaysConsumeMouseWheel: false, + }, + minimap: { + enabled: false, + }, + }; + + public editorOptionsForSelectedFile = { + ...this.editorOptions, + language: 'plaintext', + readOnly: true, + }; + + constructor( + private http: HttpClient, + private alerts: AlertService, + ) {} + + public ngOnChanges(changes: SimpleChanges): void { + if (changes['archiveFile']) { + void this.loadArchive(); + } + + if (changes['uploadRequirementNames']) { + this.applyUploadRequirementLabels(this.files); + this.rebuildFileTree(); + } + + if (changes['readOnly']) { + this.updateEditorOptions(); + } + } + + public ngOnDestroy(): void { + this.clearFiles(); + } + + public get selectedFile(): ArchiveFileEntry | null { + return this.files[this.selectedTab] ?? null; + } + + public get hasFiles(): boolean { + return this.files.length > 0; + } + + public get hasDirtyFiles(): boolean { + return this.files.some((entry) => entry.dirty); + } + + public get canSave(): boolean { + return !this.readOnly && !!this.saveEndpoint && this.hasDirtyFiles && !this.isSaving; + } + + public trackByPath(index: number, file: ArchiveFileEntry): string { + return `${index}-${file.path}`; + } + + public trackTreeNode(_index: number, node: ArchiveFileTreeNode): string { + return node.key; + } + + public selectTreeNode(node: ArchiveFileTreeNode): void { + if (node.fileIndex === null) { + return; + } + + this.selectTab(node.fileIndex); + } + + public treeNodeLabel(node: ArchiveFileTreeNode): string { + return node.fileIndex === null ? node.name : this.files[node.fileIndex]?.tabLabel || node.name; + } + + public selectTab(index: number): void { + this.selectedTab = index; + this.updateEditorOptions(); + void this.loadAndPrepareSelectedFile(); + } + + public selectedFileLanguage(): string { + const selectedFile = this.selectedFile; + if (!selectedFile) { + return 'plaintext'; + } + + return selectedFile.language ?? getMonacoLanguageForPath(selectedFile.path) ?? 'plaintext'; + } + + public onEditorChange(value: string): void { + const selectedFile = this.selectedFile; + if ( + !selectedFile || + !selectedFile.isLoaded || + this.readOnly || + !isArchiveCodeOrTextFile(selectedFile) + ) { + return; + } + + selectedFile.textContent = value; + selectedFile.dirty = selectedFile.textContent !== selectedFile.originalTextContent; + } + + public async downloadSelectedFile(): Promise { + const file = this.selectedFile; + await this.ensureFileLoaded(file); + if (!file?.blobUrl) { + return; + } + + const downloadLink = document.createElement('a'); + downloadLink.href = file.blobUrl; + downloadLink.download = file.name; + document.body.appendChild(downloadLink); + downloadLink.click(); + downloadLink.parentNode?.removeChild(downloadLink); + } + + public async saveArchive(): Promise { + if (!this.canSave || !this.saveEndpoint) { + return; + } + + this.isSaving = true; + + try { + const zip = new JSZip(); + + for (const file of this.files) { + if (file.isLoaded && isArchiveCodeOrTextFile(file) && file.textContent !== undefined) { + const encoded = new TextEncoder().encode(file.textContent); + file.data = encoded; + file.originalTextContent = file.textContent; + zip.file(file.path, encoded); + continue; + } + + if (file.data) { + zip.file(file.path, file.data); + continue; + } + + const rawData = await file.zipObject.async('uint8array'); + zip.file(file.path, rawData); + } + + const archiveBlob = await zip.generateAsync({type: 'blob'}); + const archiveUpload = new File([archiveBlob], this.saveFileName, {type: 'application/zip'}); + const formData = new FormData(); + formData.append(this.saveFieldName, archiveUpload); + + const request = + this.saveMethod === 'PUT' + ? this.http.put(this.saveEndpoint, formData, {observe: 'response'}) + : this.http.post(this.saveEndpoint, formData, {observe: 'response'}); + + const response = await firstValueFrom(request); + for (const file of this.files) { + file.dirty = false; + } + + this.alerts.success('Archive saved', 3000); + this.saveSuccess.emit(response); + } catch (error) { + this.alerts.error(`Failed to save archive: ${error}`, 6000); + this.saveError.emit(error); + } finally { + this.isSaving = false; + } + } + + private async loadArchive(): Promise { + const requestedArchive = this.archiveFile; + + this.errorMessage = null; + this.selectedTab = 0; + this.clearFiles(); + + if (!requestedArchive) { + return; + } + + this.isLoading = true; + + try { + const zipData = await requestedArchive.arrayBuffer(); + const zip = await JSZip.loadAsync(zipData); + const paths = Object.keys(zip.files).sort((a, b) => a.localeCompare(b)); + const loadedFiles: ArchiveFileEntry[] = []; + + for (const path of paths) { + const zipFile = zip.files[path]; + if (!zipFile || zipFile.dir || isArchivePathHidden(path)) { + continue; + } + + loadedFiles.push(createArchiveFilePlaceholder(path, zipFile)); + } + + if (requestedArchive !== this.archiveFile) { + this.revokeUrls(loadedFiles); + return; + } + + this.files = loadedFiles; + this.applyUploadRequirementLabels(this.files); + this.rebuildFileTree(); + this.filesLoaded.emit(this.files.length); + + if (this.files.length === 0) { + this.errorMessage = 'This archive does not contain any files.'; + this.selectedFileChanged.emit(null); + return; + } + + this.updateEditorOptions(); + if (this.showPreview || this.preloadSelectedFile) { + void this.loadAndPrepareSelectedFile(); + } else { + this.selectedFileChanged.emit(null); + } + } catch { + this.errorMessage = 'Unable to read archive. Please provide a valid zip file.'; + this.filesLoaded.emit(0); + } finally { + if (requestedArchive === this.archiveFile) { + this.isLoading = false; + } + } + } + + private clearFiles(): void { + this.revokeUrls(this.files); + this.files = []; + this.fileTreeNodes = []; + this.selectedFileChanged.emit(null); + } + + private applyUploadRequirementLabels(files: ArchiveFileEntry[]): void { + for (let fileIndex = 0; fileIndex < files.length; fileIndex++) { + const file = files[fileIndex]; + const orderedIndex = getOrderedUploadFileIndex(file.path); + const requirementIndex = orderedIndex ?? fileIndex; + const requirementName = this.uploadRequirementNames[requirementIndex]; + file.tabLabel = requirementName?.trim() || file.name; + } + } + + private rebuildFileTree(): void { + const rootNodes: ArchiveFileTreeNode[] = []; + + const getOrCreateNode = ( + siblings: ArchiveFileTreeNode[], + node: Pick, + ): ArchiveFileTreeNode => { + const existing = siblings.find( + (candidate) => + candidate.name === node.name && + candidate.path === node.path && + candidate.isDirectory === node.isDirectory, + ); + if (existing) { + if (!node.isDirectory && node.fileIndex !== null) { + existing.fileIndex = node.fileIndex; + } + return existing; + } + + const createdNode: ArchiveFileTreeNode = { + key: `${node.isDirectory ? 'dir' : 'file'}:${node.path}`, + name: node.name, + path: node.path, + isDirectory: node.isDirectory, + fileIndex: node.fileIndex, + children: [], + }; + siblings.push(createdNode); + return createdNode; + }; + + for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) { + const file = this.files[fileIndex]; + const segments = file.path.split('/').filter((segment) => segment.length > 0); + if (segments.length === 0) { + continue; + } + + let currentNodes = rootNodes; + let currentPath = ''; + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + const isFile = i === segments.length - 1; + currentPath = currentPath ? `${currentPath}/${segment}` : segment; + + const node = getOrCreateNode(currentNodes, { + name: segment, + path: currentPath, + isDirectory: !isFile, + fileIndex: isFile ? fileIndex : null, + }); + + if (!isFile) { + currentNodes = node.children; + } + } + } + + const sortNodes = (nodes: ArchiveFileTreeNode[]): void => { + nodes.sort((a, b) => { + if (a.isDirectory !== b.isDirectory) { + return a.isDirectory ? -1 : 1; + } + return a.name.localeCompare(b.name); + }); + + for (const node of nodes) { + if (node.children.length > 0) { + sortNodes(node.children); + } + } + }; + + sortNodes(rootNodes); + this.fileTreeNodes = rootNodes; + } + + private revokeUrls(files: ArchiveFileEntry[]): void { + for (const file of files) { + if (file.blobUrl) { + URL.revokeObjectURL(file.blobUrl); + } + } + } + + private async ensureFileLoaded(file: ArchiveFileEntry | null): Promise { + if (!file || file.isLoaded || file.isLoading) { + return; + } + + file.isLoading = true; + try { + const data = await file.zipObject.async('uint8array'); + const classification = classifyArchiveFile(file.path, data); + const enriched = createArchiveFileEntry(file, classification, data); + Object.assign(file, enriched); + if (file === this.selectedFile) { + this.updateEditorOptions(); + } + } catch { + file.isLoading = false; + this.alerts.error(`Unable to open file '${file.path}' from archive`, 6000); + } + } + + private async loadAndPrepareSelectedFile(): Promise { + const file = this.selectedFile; + await this.ensureFileLoaded(file); + + if (!file || file !== this.selectedFile || !file.isLoaded) { + this.selectedFileChanged.emit(null); + return; + } + + this.prepareFileForDisplay(file); + this.selectedFileChanged.emit(file); + } + + private prepareFileForDisplay(file: ArchiveFileEntry): void { + if (file.kind !== 'pdf' || !file.blob) { + return; + } + + if (file.blobUrl) { + URL.revokeObjectURL(file.blobUrl); + } + + file.blobUrl = URL.createObjectURL(file.blob); + } + + private updateEditorOptions(): void { + this.editorOptionsForSelectedFile = { + ...this.editorOptions, + language: this.selectedFileLanguage(), + readOnly: this.readOnly, + }; + } +} diff --git a/src/app/common/archive-viewer/archive-viewer.helpers.ts b/src/app/common/archive-viewer/archive-viewer.helpers.ts new file mode 100644 index 0000000000..f85d74976e --- /dev/null +++ b/src/app/common/archive-viewer/archive-viewer.helpers.ts @@ -0,0 +1,252 @@ +import * as monaco from 'monaco-editor'; +import JSZip from 'jszip'; + +export type ArchiveFileKind = 'code' | 'image' | 'pdf' | 'text' | 'binary'; + +export interface ArchiveFileClassification { + kind: ArchiveFileKind; + mimeType: string; + textContent?: string; + language?: string; +} + +export interface ArchiveFileEntry { + path: string; + name: string; + tabLabel: string; + kind: ArchiveFileKind; + mimeType: string; + language?: string; + textContent?: string; + originalTextContent?: string; + data?: Uint8Array; + blob?: Blob; + blobUrl?: string; + dirty: boolean; + isLoaded: boolean; + isLoading: boolean; + zipObject: JSZip.JSZipObject; +} + +type ArchiveFileKindLike = Pick | null | undefined; +type ArchiveFilePreviewLike = Pick | null | undefined; + +export function isArchiveCodeOrTextFile(file: ArchiveFileKindLike): boolean { + return file?.kind === 'code' || file?.kind === 'text'; +} + +export function isArchiveImageFile(file: ArchiveFilePreviewLike): boolean { + return file?.kind === 'image' && !!file.blobUrl; +} + +export function isArchivePdfFile(file: ArchiveFilePreviewLike): boolean { + return file?.kind === 'pdf' && !!file.blobUrl; +} + +export function createArchiveFilePlaceholder( + path: string, + zipObject: JSZip.JSZipObject, +): ArchiveFileEntry { + const name = getBaseName(path); + return { + path, + name, + tabLabel: name, + kind: 'binary', + mimeType: 'application/octet-stream', + dirty: false, + isLoaded: false, + isLoading: false, + zipObject, + }; +} + +export function getOrderedUploadFileIndex(path: string): number | null { + const fileName = getBaseName(path); + const match = fileName.match(/^(\d+)-/); + if (!match) { + return null; + } + + const parsed = Number.parseInt(match[1], 10); + return Number.isFinite(parsed) && parsed >= 0 ? parsed : null; +} + +export function isArchivePathHidden(path: string): boolean { + const segments = path.split('/').filter((segment) => segment.length > 0); + return segments.some((segment) => segment.startsWith('.') || segment === '__MACOSX'); +} + +export function createArchiveFileEntry( + existing: ArchiveFileEntry, + classification: ArchiveFileClassification, + data: Uint8Array, +): ArchiveFileEntry { + const blob = new Blob([data], {type: classification.mimeType}); + const shouldCreateBlobUrl = + classification.kind === 'image' || + classification.kind === 'pdf' || + classification.kind === 'binary'; + + return { + ...existing, + kind: classification.kind, + mimeType: classification.mimeType, + language: classification.language, + textContent: classification.textContent, + originalTextContent: classification.textContent, + data, + blob, + blobUrl: shouldCreateBlobUrl ? URL.createObjectURL(blob) : undefined, + dirty: false, + isLoaded: true, + isLoading: false, + }; +} + +export function classifyArchiveFile(path: string, data: Uint8Array): ArchiveFileClassification { + const detectedMimeType = detectMimeType(data); + if (detectedMimeType === 'application/pdf') { + return {kind: 'pdf', mimeType: detectedMimeType}; + } + + if (detectedMimeType.startsWith('image/')) { + return {kind: 'image', mimeType: detectedMimeType}; + } + + if (isProbablyText(data)) { + const decoded = decodeUtf8(data); + if (decoded !== null) { + const language = getMonacoLanguageForPath(path); + if (language && language !== 'plaintext') { + return {kind: 'code', mimeType: 'text/plain', textContent: decoded, language}; + } + + return {kind: 'text', mimeType: 'text/plain', textContent: decoded, language: 'plaintext'}; + } + } + + return {kind: 'binary', mimeType: detectedMimeType || 'application/octet-stream'}; +} + +export function getMonacoLanguageForPath(path: string): string | undefined { + const fileName = getBaseName(path).toLowerCase(); + const allLanguages = monaco?.languages?.getLanguages?.() ?? []; + + for (const language of allLanguages) { + if (language.filenames?.some((f) => f.toLowerCase() === fileName)) { + return language.id; + } + if (language.extensions?.some((ext) => fileName.endsWith(ext.toLowerCase()))) { + return language.id; + } + } + + return undefined; +} + +function getBaseName(path: string): string { + const lastSlash = path.lastIndexOf('/'); + return lastSlash >= 0 ? path.substring(lastSlash + 1) : path; +} + +function decodeUtf8(data: Uint8Array): string | null { + try { + return new TextDecoder('utf-8', {fatal: true}).decode(data); + } catch { + return null; + } +} + +function isProbablyText(data: Uint8Array): boolean { + if (data.length === 0) { + return true; + } + + const limit = Math.min(data.length, 8192); + let suspicious = 0; + + for (let i = 0; i < limit; i++) { + const byte = data[i]; + + if (byte === 0) { + return false; + } + + const isPrintableAscii = byte >= 32 && byte <= 126; + const isAllowedControl = byte === 9 || byte === 10 || byte === 13; + const isUtf8Extended = byte >= 128; + + if (!isPrintableAscii && !isAllowedControl && !isUtf8Extended) { + suspicious++; + } + } + + return suspicious / limit < 0.02; +} + +function detectMimeType(data: Uint8Array): string { + if (startsWithBytes(data, [0x25, 0x50, 0x44, 0x46, 0x2d])) { + return 'application/pdf'; + } + if (startsWithBytes(data, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) { + return 'image/png'; + } + if (startsWithBytes(data, [0xff, 0xd8, 0xff])) { + return 'image/jpeg'; + } + if (startsWithString(data, 'GIF87a') || startsWithString(data, 'GIF89a')) { + return 'image/gif'; + } + if (startsWithString(data, 'BM')) { + return 'image/bmp'; + } + if ( + startsWithString(data, 'RIFF') && + data.length >= 12 && + String.fromCharCode(...Array.from(data.slice(8, 12))) === 'WEBP' + ) { + return 'image/webp'; + } + if (isSvg(data)) { + return 'image/svg+xml'; + } + + return 'application/octet-stream'; +} + +function isSvg(data: Uint8Array): boolean { + const decoded = decodeUtf8(data.slice(0, 4096)); + if (!decoded) { + return false; + } + + const trimmed = decoded.trim().toLowerCase(); + return trimmed.includes(''); +} + +function startsWithBytes(data: Uint8Array, signature: number[]): boolean { + if (data.length < signature.length) { + return false; + } + + for (let i = 0; i < signature.length; i++) { + if (data[i] !== signature[i]) { + return false; + } + } + + return true; +} + +function startsWithString(data: Uint8Array, signature: string): boolean { + if (data.length < signature.length) { + return false; + } + for (let i = 0; i < signature.length; i++) { + if (data[i] !== signature.charCodeAt(i)) { + return false; + } + } + return true; +} diff --git a/src/app/common/common.coffee b/src/app/common/common.coffee index e5bbea48a2..f330d8f6ac 100644 --- a/src/app/common/common.coffee +++ b/src/app/common/common.coffee @@ -3,6 +3,5 @@ angular.module("doubtfire.common", [ 'doubtfire.common.filters' 'doubtfire.common.modals' 'doubtfire.common.file-uploader' - 'doubtfire.common.grade-icon' 'doubtfire.common.content-editable' ]) diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.html b/src/app/common/edit-profile-form/edit-profile-form.component.html index b18f430fc8..0825a194b8 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.html +++ b/src/app/common/edit-profile-form/edit-profile-form.component.html @@ -1,15 +1,23 @@ -
-
-
+ +
+
-
- - +
+
+ + -
-

{{ initialFirstName }}

- Set up your {{ externalName.value }} profile +
+

{{ user?.firstName }}

+ Set up your {{ externalName.value }} profile +
@@ -122,7 +130,7 @@

{{ initialFirstName }}

@if(tiiEnabled){
Acceptted TurnItIn EULA + >Accepted TurnItIn EULA
} diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.scss b/src/app/common/edit-profile-form/edit-profile-form.component.scss index b134972461..f40eba08d1 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.scss +++ b/src/app/common/edit-profile-form/edit-profile-form.component.scss @@ -32,3 +32,8 @@ section { font-weight: normal; } +.mat-icon { + width: 50px; + height: 50px; + font-size: 50px; +} diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.ts b/src/app/common/edit-profile-form/edit-profile-form.component.ts index a31fa6d581..34e58371c2 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.ts +++ b/src/app/common/edit-profile-form/edit-profile-form.component.ts @@ -1,11 +1,11 @@ -import { Component, Inject, Input, OnInit, Optional } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { StateService } from '@uirouter/core'; -import { User } from 'src/app/api/models/user/user'; -import { AuthenticationService } from 'src/app/api/services/authentication.service'; -import { UserService } from 'src/app/api/services/user.service'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {Component, Inject, Input, OnInit, Optional} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {StateService} from '@uirouter/core'; +import {User} from 'src/app/api/models/user/user'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'f-edit-profile-form', @@ -18,8 +18,10 @@ export class EditProfileFormComponent implements OnInit { private userService: UserService, private state: StateService, private authService: AuthenticationService, - @Optional() @Inject(MAT_DIALOG_DATA) public data: { user: User; mode: 'edit' | 'create' | 'new' }, - private _snackBar: MatSnackBar + @Optional() + @Inject(MAT_DIALOG_DATA) + public data: {user: User; mode: 'edit' | 'create' | 'new'; modal: boolean}, + private _snackBar: MatSnackBar, ) { this.user = data?.user || this.userService.currentUser; } @@ -31,11 +33,12 @@ export class EditProfileFormComponent implements OnInit { * new is used for creating a new user */ @Input() mode: 'edit' | 'create' | 'new'; + @Input() modal: boolean = false; public user: User; public externalName = this.constants.ExternalName; public initialFirstName: string; - public formPronouns = { pronouns: '' }; + public formPronouns = {pronouns: ''}; public get customPronouns(): boolean { return this.formPronouns.pronouns === '__customPronouns'; } @@ -44,9 +47,8 @@ export class EditProfileFormComponent implements OnInit { if (this.data?.mode) { this.mode = this.data.mode; } - - if (this.userService.isAnonymousUser()) { - this.state.go('sign_in'); + if (this.data?.modal) { + this.modal = this.data.modal; } this.user.optInToResearch = false; diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.html b/src/app/common/feedback-template-editor/feedback-template-editor.component.html new file mode 100644 index 0000000000..7981c9aeaf --- /dev/null +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.html @@ -0,0 +1,264 @@ +
+
+

Edit Feedback Templates for Outcome

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + folder + + + description + + Parent + {{ getParentChipText(feedbackTemplate.parentChipId) }} + Chip Text + {{ feedbackTemplate.chipText }} + Description + {{ feedbackTemplate.description }} + Comment Text + {{ feedbackTemplate.commentText }} + Summary Text + {{ feedbackTemplate.type === 'group' ? '' : feedbackTemplate.summaryText }} + Task Status + @if (feedbackTemplate.taskStatus) { + + + {{ taskService.statusData(feedbackTemplate.taskStatus).label }} + + } + + @if (feedbackTemplateHasChanges(feedbackTemplate)) { + + } + +
+ + +
+ + + +
+ + + @if (context) { + + + + + } + +
+ + @if (selectedTemplate) { +
+

Edit Template

+ +
+ @if (selectedTemplate.isNew) { + + Type + + Group + Template + + + } + + + Parent + + + {{ parent.chipText }} + + + + + + Chip Text + + + + + Description + + +
+ + @if (selectedTemplate.type === 'template') { + + Comment Text + + + +
+ + Summary Text + + + + + Task Status + + + + {{ taskService.statusData(status).label }} + + + +
+ } + +
+ + +
+
+ } +
+
+
diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.ts b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts new file mode 100644 index 0000000000..8d97643141 --- /dev/null +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts @@ -0,0 +1,327 @@ +import { + AfterViewInit, + Component, + Inject, + Input, + OnChanges, + SimpleChanges, + ViewChild, +} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSelectChange} from '@angular/material/select'; +import { + TaskDefinition, + Unit, + LearningOutcome, + FeedbackTemplate, + TaskService, + FeedbackTemplateService, +} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {MatSort, Sort} from '@angular/material/sort'; +import { + confirmationModal, + csvResultModalService, + csvUploadModalService, +} from 'src/app/ajs-upgraded-providers'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; + +@Component({ + selector: 'f-feedback-template-editor', + templateUrl: 'feedback-template-editor.component.html', +}) +export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit { + @Input() context?: TaskDefinition | Unit; + @Input() selectedOutcome: LearningOutcome; + + @ViewChild('templateTable', {static: false}) templateTable: MatTable; + @ViewChild(MatSort, {static: false}) templateSort: MatSort; + @ViewChild(MatPaginator, {static: false}) templatePaginator: MatPaginator; + + public templateSource: MatTableDataSource; + public templateColumns: string[] = [ + 'icon', + 'parent', + 'chipText', + 'description', + 'commentText', + 'summaryText', + 'taskStatus', + 'feedbackTemplateAction', + ]; + public selectedTemplate: FeedbackTemplate; + public possibleParents: FeedbackTemplate[]; + + constructor( + private alerts: AlertService, + private feedbackTemplateService: FeedbackTemplateService, + private fileDownloaderService: FileDownloaderService, + private taskService: TaskService, + @Inject(csvResultModalService) private csvResultModalService: any, + @Inject(csvUploadModalService) private csvUploadModal: any, + @Inject(confirmationModal) private confirmationModal: any, + ) {} + + ngAfterViewInit(): void { + this.getFeedbackChips(); + } + + ngOnChanges(changes: SimpleChanges): void { + this.selectedTemplate = null; + this.getFeedbackChips(); + } + + initialiseTable(feedbackTemplates: FeedbackTemplate[]) { + this.templateSource = new MatTableDataSource(feedbackTemplates); + this.templateSource.paginator = this.templatePaginator; + this.templateSource.sort = this.templateSort; + this.templateSource.filterPredicate = (data: FeedbackTemplate, filter: string) => { + const filterValue = filter.trim().toLowerCase(); + return ( + this.getParentChipText(data.parentChipId).toLowerCase().includes(filterValue) || + data.chipText.toLowerCase().includes(filterValue) || + data.commentText?.toLowerCase().includes(filterValue) || + data.summaryText?.toLowerCase().includes(filterValue) || + data.description.toLowerCase().includes(filterValue) + ); + }; + this.sortTemplateData({active: 'chipText', direction: 'asc'}); + } + + public getFeedbackChips() { + this.feedbackTemplateService.cache.values.subscribe((templates) => { + const outcomeTemplates = templates.filter( + (temp) => temp.learningOutcomeId === this.selectedOutcome.id, + ); + this.possibleParents = outcomeTemplates.filter((temp) => temp.type === 'group'); + this.initialiseTable(outcomeTemplates); + }); + } + + public saveFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + if ( + !feedbackTemplate.chipText.trim() || + !feedbackTemplate.description.trim() || + (feedbackTemplate.type === 'template' && + (!feedbackTemplate.commentText.trim() || !feedbackTemplate.summaryText.trim())) + ) { + this.alerts.error('Failed to save feedback template. Fill in required fields.'); + return; + } + feedbackTemplate.save().subscribe({ + next: () => { + this.alerts.success('Template saved'); + feedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + this.selectFeedbackTemplate(this.selectedTemplate); + }, + error: () => this.alerts.error('Failed to save feedback template. Please try again.'), + }); + } + + public selectFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + if (this.selectedTemplate === feedbackTemplate) { + this.selectedTemplate = null; + } else { + this.selectedTemplate = feedbackTemplate; + + if (!this.selectedTemplate.hasOriginalSaveData) { + this.selectedTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + } + } + } + + public sortTemplateData(sort: Sort) { + sort.active = sort.active || 'chipText'; + sort.direction = sort.direction || 'asc'; + + const isAsc = sort.direction === 'asc'; + + // Generic sorting function for dynamic property access + const compare = (a: FeedbackTemplate, b: FeedbackTemplate) => { + const key = sort.active as keyof FeedbackTemplate; + const aValue = a[key]; + const bValue = b[key]; + + if (typeof aValue === 'string' && typeof bValue === 'string') { + return aValue.localeCompare(bValue) * (isAsc ? 1 : -1); + } + return 0; + }; + + // Initial sorting by the chosen method + const sortedTemplates = [...this.templateSource.data].sort(compare); + + // Determine maximum depth of the hierarchy (only groups contribute to depth) + const depthMap = new Map(); + let maxDepth = 0; + + const feedbackGroups = sortedTemplates.filter((t) => t.type === 'group'); + const feedbackTemplates = sortedTemplates.filter((t) => t.type !== 'group'); + + feedbackGroups.forEach((template) => { + let depth = 0; + let parentId = template.parentChipId; + + while (parentId) { + depth++; + parentId = sortedTemplates.find((t) => t.id === parentId)?.parentChipId ?? null; + } + + depthMap.set(template.id, depth); + maxDepth = Math.max(maxDepth, depth); + }); + + // Assign sequential order numbers + const orderMap = new Map(); + let orderIndex = 1; + + sortedTemplates.forEach((template) => { + orderMap.set(template.id, orderIndex++); + }); + + feedbackGroups.sort((a, b) => depthMap.get(a.id)! - depthMap.get(b.id)!); + + // Assign hierarchical order to groups using depth-based multiplier + feedbackGroups.forEach((template) => { + const parentOrder = template.parentChipId ? orderMap.get(template.parentChipId)! : 0; + const depth = depthMap.get(template.id) ?? 0; + const multiplier = 10 ** (maxDepth + 5 - depth * 3); // Proper scaling based on depth + + orderMap.set(template.id, parentOrder + orderMap.get(template.id)! * multiplier); + }); + + // Assign order values to templates by directly adding their parent's order + feedbackTemplates.forEach((template) => { + const parentOrder = orderMap.get(template.parentChipId) ?? 0; + orderMap.set(template.id, parentOrder + orderMap.get(template.id)!); + }); + + // Sort again by computed hierarchical order + sortedTemplates.sort((a, b) => orderMap.get(a.id)! - orderMap.get(b.id)!); + + // Update the data source + this.templateSource.data = [...sortedTemplates]; + } + + applyFilter(filterValue: string) { + this.templateSource.filter = filterValue; + if (this.templateSource.paginator) { + this.templateSource.paginator.firstPage(); + } + } + + public feedbackTemplateHasChanges(feedbackTemplate: FeedbackTemplate): boolean { + return feedbackTemplate.hasChanges(this.feedbackTemplateService.mapping); + } + + public deleteFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + this.confirmationModal.show( + 'Delete feedback template', + 'Are you sure you want to delete this template? This action is final.', + () => { + feedbackTemplate.delete().subscribe({ + next: () => { + this.alerts.success('Feedback template deleted'); + if (this.selectedTemplate === feedbackTemplate) + this.selectFeedbackTemplate(this.selectedTemplate); + }, + error: () => this.alerts.error('Failed to delete feedback template. Please try again.'), + }); + }, + ); + } + + public uploadCsv() { + const url = this.selectedOutcome.getFeedbackTemplateBatchUploadUrl(); + + this.csvUploadModal.show( + 'Upload Feedback Templates as CSV', + 'Test message', + {file: {name: 'Feedback Templates CSV Data', type: 'csv'}}, + url, + (response: any) => { + this.csvResultModalService.show('Feedback Templates CSV Upload Results', response); + if (response.success.length > 0) { + let contextType: 'units' | 'task_definitions'; + + if (this.context instanceof Unit) { + this.context.refresh(); + contextType = 'units'; + } else if (this.context instanceof TaskDefinition) { + this.context.unit.refresh(); + contextType = 'task_definitions'; + } + if (contextType) { + this.feedbackTemplateService + .fetchAll({contextType, contextId: this.context.id}, {}) + .subscribe({ + next: () => this.getFeedbackChips(), + error: () => this.alerts.error('Error loading task feedback templates.'), + }); + } + } + }, + ); + } + + public downloadCsv() { + const url = this.selectedOutcome.getFeedbackTemplateBatchUploadUrl(); + let name = `${this.selectedOutcome.abbreviation}-FeedbackTemplates.csv`; + + if (this.context instanceof TaskDefinition) + name = `${this.context.unit.code}-${this.context.abbreviation}-${name}`; + else if (this.context instanceof Unit) name = `${this.context.code}-${name}`; + + this.fileDownloaderService.downloadFile(url, name); + } + + public createFeedbackTemplate() { + if (this.selectedOutcome.isNew) { + this.alerts.error('Save the new outcome to proceed.'); + return; + } + + const feedbackTemplate = new FeedbackTemplate(); + + feedbackTemplate.type = 'template'; + feedbackTemplate.chipText = ''; + feedbackTemplate.description = ''; + feedbackTemplate.commentText = ''; + feedbackTemplate.summaryText = ''; + feedbackTemplate.learningOutcomeId = this.selectedOutcome.id; + + this.selectedTemplate = feedbackTemplate; + } + + onTemplateTypeChange(event: MatSelectChange): void { + if (!this.selectedTemplate.isNew) { + this.alerts.error('Template type change forbidden.'); + event.source.writeValue(this.selectedTemplate.type); + } else { + this.selectedTemplate.type = event.value; + } + } + + getPossibleParents(): FeedbackTemplate[] { + if (!this.selectedTemplate.isNew) + return this.possibleParents.filter( + (p) => p.id != this.selectedTemplate.id && !this.isAncestor(this.selectedTemplate.id, p), + ); + else return this.possibleParents; + } + + isAncestor(idToCheck: number, descendant: FeedbackTemplate): boolean { + if (descendant.parentChipId === idToCheck) return true; + + const parent = this.possibleParents.find((p) => p.id === descendant.parentChipId); + if (!parent) return false; + + return this.isAncestor(idToCheck, parent); + } + + getParentChipText(parentId: number): string { + const parent = this.possibleParents.find((p) => p.id === parentId); + return parent ? parent.chipText : ''; + } +} diff --git a/src/app/common/file-downloader/file-downloader.service.ts b/src/app/common/file-downloader/file-downloader.service.ts index 3b549edbd6..57b8fff783 100644 --- a/src/app/common/file-downloader/file-downloader.service.ts +++ b/src/app/common/file-downloader/file-downloader.service.ts @@ -2,6 +2,16 @@ import {HttpClient, HttpResponse} from '@angular/common/http'; import {Injectable} from '@angular/core'; import {AlertService} from '../services/alert.service'; +interface FileDownloaderData { + url: string; + response: HttpResponse; + success: (url: string, response: HttpResponse) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + failure: (error: any) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + binaryData: Blob[]; +} + @Injectable({ providedIn: 'root', }) @@ -11,20 +21,99 @@ export class FileDownloaderService { private alerts: AlertService, ) {} + private processPartialBlob(data: FileDownloaderData) { + // We now need to ask for the next part of the file + const range = data.response.headers.get('Content-Range'); + if (range) { + // The range header is in the format "bytes start-end/totalSize" + const parts = range.split('/'); + + // Split into the range and the total size + if (parts.length === 2) { + // Parse the total size and the range + const totalSize = parseInt(parts[1], 10); + + // Extract the range after the "bytes" part + const contentRange = parts[0].split(' ')[1]; + + // Extract the parts of the range + const contentRangeParts = contentRange.split('-'); + + // If we have two parts, we have a valid range and size + if (contentRangeParts.length === 2) { + const start = parseInt(contentRangeParts[0], 10); + const end = parseInt(contentRangeParts[1], 10); + + // Check the start is the same as the length of the binary data received + if (start !== data.binaryData.map((value) => value.size).reduce((pv, cv) => pv + cv, 0)) { + console.log('Error: start != oldLen'); + this.alerts.error('Error downloading file part received out of order'); + } + data.binaryData.push(data.response.body); + + // If the end is less than the total size, we need to request the next part + if (end + 1 < totalSize) { + const rangeHeader = {Range: `bytes=${end + 1}-${totalSize}`}; + this.httpClient + .get(data.url, {responseType: 'blob', observe: 'response', headers: rangeHeader}) + .subscribe({ + next: (response2) => { + data.response = response2; + this.processHttpResponse(data); + }, + error: (error) => { + if (data.failure) data.failure(error); + }, + }); + return; + } else { + // we have all of the data, so we can report success + this.reportSuccess(data); + } + } + } + } else { + // no range... so we can't do anything! + console.log('Error reading response from server - no range with 206 response'); + if (data.failure) data.failure('Unable to read data from server'); + } + } + + private processHttpResponse(data: FileDownloaderData) { + // Check if we have a partial content response + if (data.response.status === 206) { + this.processPartialBlob(data); + } else { + // Save the binary data we have received so far + data.binaryData.push(data.response.body); + this.reportSuccess(data); + } + } + + private reportSuccess(data: FileDownloaderData) { + const resourceUrl: string = window.URL.createObjectURL( + new Blob(data.binaryData, {type: data.response.body.type}), + ); + data.success(resourceUrl, data.response); + } + public downloadBlob( url: string, success: (url: string, response: HttpResponse) => void, - failure: (error: any) => void, + failure: (error) => void, ) { + // Declare binary data outside of the subscription so that it can be accessed in the second requests when partial content is returned + const binaryData = []; + this.httpClient.get(url, {responseType: 'blob', observe: 'response'}).subscribe({ next: (response) => { - const binaryData = []; - binaryData.push(response.body); - // response.headers.get('content-type') - const resourceUrl: string = window.URL.createObjectURL( - new Blob(binaryData, {type: response.body.type}), - ); - success(resourceUrl, response); + this.processHttpResponse({ + url: url, + response: response, + success: success, + failure: failure, + binaryData: binaryData, + }); }, error: (error) => { if (failure) failure(error); @@ -36,28 +125,42 @@ export class FileDownloaderService { window.URL.revokeObjectURL(url); } + /** + * Download or save a blob to a file. This will trigger the user to "download" + * the blob, with the suggested filename. + * + * @param blobUrl the url of the blob to download/save to file + * @param filename the name of the file + */ + public downloadBlobToFile(blobUrl: string, filename: string): void { + const downloadLink = document.createElement('a'); + downloadLink.href = blobUrl; + downloadLink.target = '_blank'; + downloadLink.setAttribute('download', filename); + document.body.appendChild(downloadLink); + + downloadLink.click(); + downloadLink.parentNode.removeChild(downloadLink); + } + public downloadFile(url: string, defaultFilename: string) { this.downloadBlob( url, (resourceUrl: string, response: HttpResponse) => { - const downloadLink = document.createElement('a'); - downloadLink.href = resourceUrl; - downloadLink.target = '_blank'; const filenameRegex = /filename[^;=\n]*=((['']).*?\2|[^;\n]*)/; + const matches = filenameRegex.exec(response.headers.get('Content-Disposition')); + let filename: string; + if (matches != null && matches[1]) { - const filename = matches[1].replace(/['']/g, ''); - downloadLink.setAttribute('download', filename); + filename = matches[1].replace(/['']/g, ''); } else { - downloadLink.setAttribute('download', defaultFilename); + filename = defaultFilename; } - document.body.appendChild(downloadLink); - - downloadLink.click(); - downloadLink.parentNode.removeChild(downloadLink); + this.downloadBlobToFile(resourceUrl, filename); }, - (error: any) => { + (error) => { this.alerts.error(`Error downloading file - ${error}`); }, ); diff --git a/src/app/common/file-uploader/file-uploader.coffee b/src/app/common/file-uploader/file-uploader.coffee index 9f8dac5ff9..89c0c17755 100644 --- a/src/app/common/file-uploader/file-uploader.coffee +++ b/src/app/common/file-uploader/file-uploader.coffee @@ -68,7 +68,7 @@ angular.module('doubtfire.common.file-uploader', ["ngFileUpload"]) extensions: ['pas', 'cpp', 'c', 'cs', 'csv', 'h', 'hpp', 'java', 'py', 'js', 'html', 'coffee', 'rb', 'css', 'scss', 'yaml', 'yml', 'xml', 'json', 'ts', 'r', 'rmd', 'rnw', 'rhtml', 'rpres', 'tex', 'vb', 'sql', 'txt', 'md', 'jack', 'hack', 'asm', 'hdl', 'tst', 'out', 'cmp', 'vm', 'sh', 'bat', - 'dat', 'ipynb', 'pml'] + 'dat', 'ipynb', 'pml', 'vue'] icon: 'fa-file-code-o' name: 'code' image: @@ -263,7 +263,7 @@ angular.module('doubtfire.common.file-uploader', ["ngFileUpload"]) response = JSON.parse xhr.responseText catch e if xhr.status is 0 - response = { error: 'Could not connect to the Doubtfire server' } + response = { error: 'Could not connect to the OnTrack server' } else response = xhr.responseText # Success (20x success range) diff --git a/src/app/common/filters/tasks-by-tutor.pipe.ts b/src/app/common/filters/tasks-by-tutor.pipe.ts new file mode 100644 index 0000000000..d99da5564b --- /dev/null +++ b/src/app/common/filters/tasks-by-tutor.pipe.ts @@ -0,0 +1,21 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {Task, UnitRole} from '../../api/models/doubtfire-model'; + +@Pipe({ + name: 'tasksByTutor', +}) +export class TasksByTutorPipe implements PipeTransform { + transform(currentUnitRole: UnitRole, tasks: Task[], unitRoleId?: number | string): Task[] { + if (!tasks) return tasks; + + if (!unitRoleId || unitRoleId === 'all') return tasks; + + if (unitRoleId === 'mentoring_all') { + if (!currentUnitRole) return []; + + return tasks.filter((task) => task.tutor?.mentorId === currentUnitRole.id); + } + + return tasks.filter((task) => task.tutor?.id === unitRoleId); + } +} diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 7e28c72b32..cb6e238c38 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,40 +1,45 @@ @if (selectedTask?.similaritiesDetected) { -
-
-

- Similarities flagged for {{ selectedTask?.project.student.name }} -

-
+
+

+ Similarities flagged for {{ selectedTask?.project?.student.name }} +

+
} -
- + + +
+ - - + +
- - + + @if (selectedTask && selectedTask.suggestedTaskStatus) { + + } + + + @if (selectedTask?.definition?.assessInPortfolioOnly) { + + } @else { +
+ +
+ }
+
+ +
+ +
+ @if (viewType !== 'moderation' && !hideMainActionButtonsForModeration) { + + } + + @if (selectedTask && !selectedTask.loadingSubmissionDetails) { + @if (viewType === 'moderation') { +
+
+ @if (!hideMainActionButtonsForModeration) { + + + } @else { + + } + + + + + @if (hideMainActionButtonsForModeration) { + + } @else { + + } + +
+
+ } + @if (viewType === 'overflow' || selectedTask.claimedByUnitRoleId) { + + } + } +
@if (selectedTask?.similaritiesDetected) { - +
+ + + +
} + @if (selectedTask?.project) { + @if (selectedTask?.definition.discussionPromptsCount) { + + } + + @if (canAccessTutorNotes) { +
+ +
+ } + +
+ @if (selectedTask.project.staffNoteCount > 0) { +
+ } + +
+ } + - + + + + + @if (!selectedTask?.hasPdf && selectedTask?.status === 'ready_for_feedback') { + + } - @@ -141,12 +344,20 @@ file_download - {{ selectedTask?.project.targetGradeAcronym }} + {{ + selectedTask?.project?.targetGradeAcronym + }}
diff --git a/src/app/common/footer/footer.component.scss b/src/app/common/footer/footer.component.scss index ca55371d54..77929ba541 100644 --- a/src/app/common/footer/footer.component.scss +++ b/src/app/common/footer/footer.component.scss @@ -22,6 +22,15 @@ .large-button:hover { background-color: #f5f5f5; } + + .extra-large-button { + padding-top: 7px; + transform: scale(1.25); + } + + .extra-large-button:hover { + filter: brightness(0.85); + } } .small-icon { @@ -39,3 +48,31 @@ margin-right: 25px; } } + +@import '../../../styles/mixins/task-status-colors-generator.scss'; + +@mixin status-icon($status) { + background-color: task-status-color($status); + color: task-status-color($status, fore); +} + +.status-chip { + &.feedback-exceeded { + @include status-icon('feedback-exceeded'); + } + &.redo { + @include status-icon('redo'); + } + &.fix-and-resubmit { + @include status-icon('fix-and-resubmit'); + } + &.discuss { + @include status-icon('discuss'); + } + &.complete { + @include status-icon('complete'); + } + &.assess-in-portfolio { + @include status-icon('assess-in-portfolio'); + } +} diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index 2e4d3ff1ef..7626b63a6d 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -1,9 +1,12 @@ -import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Task } from 'src/app/api/models/task'; -import { SelectedTaskService } from 'src/app/projects/states/dashboard/selected-task.service'; - -import { FileDownloaderService } from '../file-downloader/file-downloader.service'; +import {Component, ElementRef, HostListener, Input, OnInit, ViewChild} from '@angular/core'; +import {Observable} from 'rxjs'; +import {Task} from 'src/app/api/models/task'; +import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; +import {TaskService} from 'src/app/api/services/task.service'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; +import {TaskAssessmentModalService} from '../modals/task-assessment-modal/task-assessment-modal.service'; +import {UnitRole} from 'src/app/api/models/unit-role'; +import {UserService} from 'src/app/api/services/user.service'; @Component({ selector: 'f-footer', @@ -11,13 +14,23 @@ import { FileDownloaderService } from '../file-downloader/file-downloader.servic styleUrls: ['./footer.component.scss'], }) export class FooterComponent implements OnInit { - constructor(public selectedTaskService: SelectedTaskService, private fileDownloader: FileDownloaderService) {} + constructor( + public selectedTaskService: SelectedTaskService, + public taskService: TaskService, + private fileDownloader: FileDownloaderService, + private taskAssessmentModal: TaskAssessmentModalService, + private userService: UserService, + ) {} + + @Input() viewType: 'inbox' | 'explorer' | 'moderation' | 'overflow'; selectedTask$: Observable; selectedTask: Task; + public showModerationStatusButtons = false; - @ViewChild('similaritiesButton', { static: false, read: ElementRef }) similaritiesButton: ElementRef; - @ViewChild('warningText', { static: false, read: ElementRef }) warningText: ElementRef; + @ViewChild('similaritiesButton', {static: false, read: ElementRef}) + similaritiesButton: ElementRef; + @ViewChild('warningText', {static: false, read: ElementRef}) warningText: ElementRef; public leftOffset: number; public topOffset: number; public warningTextLeftOffset: number; @@ -37,7 +50,33 @@ export class FooterComponent implements OnInit { const totalPaddingOffset = 30; this.warningTextLeftOffset = - this.leftOffset - (this.warningText?.nativeElement.getBoundingClientRect().width + totalPaddingOffset) / 2; + this.leftOffset - + (this.warningText?.nativeElement.getBoundingClientRect().width + totalPaddingOffset) / 2; + } + + public get canAccessTutorNotes(): boolean { + const tutor = this.selectedTask.tutor; + if (!tutor) { + return false; + } + + if (!this.currentUnitRole) { + return false; + } + + // Ensure the unit is mapped correctly to access the mentor + tutor.unit = this.selectedTask.unit; + + const canAccess = + this.currentUnitRole.role === 'Convenor' || + this.currentUnitRole.role === 'Admin' || + (tutor.mentor && tutor.mentor.id === this.currentUnitRole.id); + + return canAccess; + } + + public viewTutorNotes() { + this.selectedTaskService.showTutorNotes(); } ngOnInit(): void { @@ -46,6 +85,7 @@ export class FooterComponent implements OnInit { this.selectedTask$.subscribe((task) => { this.selectedTask = task; + // We need to timeout to give the DOM a chance to place the elements setTimeout(() => { this.findSimilaritiesButton(); @@ -56,17 +96,29 @@ export class FooterComponent implements OnInit { downloadFiles() { this.fileDownloader.downloadFile( this.selectedTask.submittedFilesUrl(true), - `${this.selectedTask.project.student.lastName}-${this.selectedTask.definition.name}.zip` + `${this.selectedTask.project.student.lastName}-${this.selectedTask.definition.name}.zip`, ); } downloadSubmissionPdf() { this.fileDownloader.downloadFile( this.selectedTask.submissionUrl(true), - `${this.selectedTask.project.student.lastName}-${this.selectedTask.definition.name}.pdf` + `${this.selectedTask.project.student.lastName}-${this.selectedTask.definition.name}.pdf`, ); } + markTaskWorkingOnIt(task?: Task) { + if (!task || !task.definition?.assessInPortfolioOnly) { + return; + } + task.addComment( + `**Automated Message:** Task "${task.definition.abbreviation} ${task.definition.name}" will be graded during portfolio assessment only. You can keep submitting it for feedback before the task deadline, but you must still submit it directly for portfolio assessment before the portfolio deadline.`, + ); + setTimeout(() => { + task.updateTaskStatus('working_on_it'); + }, 500); + } + viewTaskSheet() { this.selectedTaskService.showTaskSheet(); } @@ -78,4 +130,65 @@ export class FooterComponent implements OnInit { viewSimilarity() { this.selectedTaskService.showSimilarity(); } + + // viewOverseer() { + // this.taskAssessmentModal.show(this.selectedTask); + // } + + viewOverseer() { + this.selectedTaskService.showOverseerReports(); + } + + viewStaffNotes() { + this.selectedTaskService.showStaffNotes(); + } + + viewDiscussionPrompts() { + this.selectedTaskService.showDiscussionPrompts(); + } + + getJplagReport() { + if (!this.selectedTask?.definition) { + return; + } + this.fileDownloader.downloadFile( + this.selectedTask.definition.getJplagReportUrl(), + `${this.selectedTask.definition.abbreviation}-jplag-report`, + ); + } + + public get currentUnitRole(): UnitRole | undefined { + const currentUser = this.userService.currentUser; + return this.selectedTask.unit.staff.find((ur) => ur.user.id === currentUser.id); + } + + public get actionButtonEnabled(): boolean { + if (!this.selectedTask) { + return false; + } + + if (this.selectedTask.loadingSubmissionDetails) { + return false; + } + + if (this.viewType === 'overflow' || this.selectedTask.claimedByUnitRoleId) { + if (this.currentUnitRole.id !== this.selectedTask.claimedByUnitRoleId) { + return false; + } + } + + return true; + } + + public get completeButtonEnabled(): boolean { + return this.actionButtonEnabled && !!this.selectedTask?.canMarkComplete; + } + + public get hideMainActionButtonsForModeration(): boolean { + return this.viewType === 'moderation' && !this.showModerationStatusButtons; + } + + public toggleModerationStatusButtons() { + this.showModerationStatusButtons = !this.showModerationStatusButtons; + } } diff --git a/src/app/common/grade-icon/grade-icon.coffee b/src/app/common/grade-icon/grade-icon.coffee deleted file mode 100644 index f35f7fbfa4..0000000000 --- a/src/app/common/grade-icon/grade-icon.coffee +++ /dev/null @@ -1,16 +0,0 @@ -angular.module('doubtfire.common.grade-icon', []) - -.directive 'gradeIcon', -> - restrict: 'E' - replace: true - templateUrl: 'common/grade-icon/grade-icon.tpl.html' - scope: - inputGrade: '=?grade' - colorful: '=?' - controller: ($scope, gradeService) -> - $scope.$watch 'inputGrade', (newGrade) -> - $scope.grade = if _.isString($scope.inputGrade) then gradeService.stringToGrade($scope.inputGrade) else $scope.inputGrade - $scope.gradeText = (grade) -> - if grade? then gradeService.grades[grade] or "Grade" - $scope.gradeLetter = (grade) -> - gradeService.gradeAcronyms[grade] or 'G' diff --git a/src/app/common/grade-icon/grade-icon.component.html b/src/app/common/grade-icon/grade-icon.component.html new file mode 100644 index 0000000000..7af15c0ba3 --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.html @@ -0,0 +1,16 @@ +
+ + {{ gradeLetter }} + +
diff --git a/src/app/common/grade-icon/grade-icon.component.scss b/src/app/common/grade-icon/grade-icon.component.scss new file mode 100644 index 0000000000..7bcb77deaa --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.scss @@ -0,0 +1,6 @@ +.text-left .grade-icon { + margin-left: 0; +} +.text-right .grade-icon { + margin-right: 0; +} diff --git a/src/app/common/grade-icon/grade-icon.component.ts b/src/app/common/grade-icon/grade-icon.component.ts new file mode 100644 index 0000000000..5f8f31c7bc --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.ts @@ -0,0 +1,35 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {GradeService} from '../services/grade.service'; + +@Component({ + selector: 'f-grade-icon', + templateUrl: './grade-icon.component.html', + styleUrls: ['./grade-icon.component.scss'], +}) +export class GradeIconComponent implements OnInit, OnChanges { + @Input() grade?: number | string; + @Input() colorful: boolean = false; + + gradeText: string = 'Grade'; + gradeLetter: string = 'G'; + + constructor(private gradeService: GradeService) {} + + ngOnInit(): void { + this.updateGrade(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['grade']) { + this.updateGrade(); + } + } + + private updateGrade(): void { + const grade: number = + typeof this.grade === 'string' ? this.gradeService.stringToGrade(this.grade) : this.grade; + this.gradeText = this.gradeService.grades[grade] || 'Grade'; + this.gradeLetter = this.gradeService.gradeAcronyms[grade] || 'G'; + } +} diff --git a/src/app/common/grade-icon/grade-icon.scss b/src/app/common/grade-icon/grade-icon.scss deleted file mode 100644 index 08db661a8b..0000000000 --- a/src/app/common/grade-icon/grade-icon.scss +++ /dev/null @@ -1,48 +0,0 @@ -.grade-icon.text-muted { - background-color: $text-muted; -} -.grade-icon.text-primary { - background-color: $brand-primary; -} -.grade-icon.text-success { - background-color: $brand-success; -} -.grade-icon.text-danger { - background-color: $brand-danger; -} -.grade-icon.text-info { - background-color: $brand-info; -} -.grade-icon.text-warning { - background-color: $brand-warning; -} -a .grade-icon:hover { - background-color: $link-hover-color; -} -.grade-icon { - color: #fff; - font-size: 1em; - background-color: $text-color; - border-radius: 100%; - width: 2.25em; - height: 2.25em; - font-weight: 100; - font-size: 1em; - @include no-select; - margin: 0 auto; - display: flex; - align-items: center; - justify-content: center; -} -.grade-icon.colorful { - &.grade-0 { background-color: $grade-color-p; } - &.grade-1 { background-color: $grade-color-c; } - &.grade-2 { background-color: $grade-color-d; } - &.grade-3 { background-color: $grade-color-hd; } -} -.text-left .grade-icon { - margin-left: 0; -} -.text-right .grade-icon { - margin-right: 0; -} diff --git a/src/app/common/grade-icon/grade-icon.tpl.html b/src/app/common/grade-icon/grade-icon.tpl.html deleted file mode 100644 index 1939b21361..0000000000 --- a/src/app/common/grade-icon/grade-icon.tpl.html +++ /dev/null @@ -1,8 +0,0 @@ -
- - {{gradeLetter(grade)}} - -
diff --git a/src/app/common/header/header.component.html b/src/app/common/header/header.component.html index bac6b77c07..76e5022622 100644 --- a/src/app/common/header/header.component.html +++ b/src/app/common/header/header.component.html @@ -5,6 +5,12 @@ style="min-height: 85px" > @if (!media.isActive('xs')) { + @if (logoSettings.hasLogo) { + + + + } + - + @if (sidekiqJobs.length) { + + } + @if (currentUnit && currentUnitRole && currentUnitRole.tutorNoteCount > 0) { + + + } + @if (currentUnit) { + + } @if (currentUser.role === 'Admin' || currentUser.role === 'Convenor') { - + + + @if (isMentor || unitRole.role === 'Convenor') { + + } + + @if (canMarkOverflowTask) { + + } + + - @@ -144,7 +164,16 @@ - @if (unitRole.role === 'Convenor' || unitRole.role === 'Admin' || unitRole.role === 'Auditor') { + + @if ( + unitRole.role === 'Convenor' || unitRole.role === 'Admin' || unitRole.role === 'Auditor' + ) { + + + } + + + + + + + + @if (selectedOutcome) { +
+
+

Edit Outcome

+ +
+ + Abbreviation + + + + + Short Description + + +
+ + + Full Outcome Description + + + + @if (abbreviationPrefix !== 'GLO') { + + Connected Learning Outcomes + + @for (outcome of selectedConnectedOutcomes(); track outcome.abbreviation) { + + {{ outcome.abbreviation }} + + + } + + + + @for (outcome of filteredOutcomes(); track outcome) { + {{ outcome.abbreviation }} - {{ outcome.shortDescription }} + } + + + } + +
+ + +
+
+
+ + + } +
diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts new file mode 100644 index 0000000000..3dfa2451cf --- /dev/null +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts @@ -0,0 +1,397 @@ +import { + AfterViewInit, + Component, + computed, + inject, + Inject, + Input, + model, + OnDestroy, + signal, + effect, + ViewChild, + OnChanges, + SimpleChanges, +} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {MatPaginator} from '@angular/material/paginator'; +import { + TaskDefinition, + Unit, + LearningOutcome, + LearningOutcomeService, + TaskService, + FeedbackTemplateService, +} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {MatSort, Sort} from '@angular/material/sort'; +import { + confirmationModal, + csvResultModalService, + csvUploadModalService, +} from 'src/app/ajs-upgraded-providers'; +import {Subscription} from 'rxjs'; +import {COMMA, ENTER} from '@angular/cdk/keycodes'; +import {LiveAnnouncer} from '@angular/cdk/a11y'; +import {MatChipInputEvent} from '@angular/material/chips'; +import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; +import {isEqual} from 'lodash'; +import {NestedCsvDownloadModalService} from './nested-csv-download-modal/nested-csv-download-modal.service'; +import API_URL from 'src/app/config/constants/apiUrl'; + +@Component({ + selector: 'f-learning-outcome-editor', + templateUrl: 'learning-outcome-editor.component.html', +}) +export class LearningOutcomeEditorComponent implements OnChanges, AfterViewInit, OnDestroy { + @Input() context?: TaskDefinition | Unit; + + @ViewChild('outcomeTable', {static: false}) outcomeTable: MatTable; + @ViewChild(MatSort, {static: false}) outcomeSort: MatSort; + @ViewChild(MatPaginator, {static: false}) outcomePaginator: MatPaginator; + + public outcomeSource: MatTableDataSource; + public outcomeColumns: string[] = [ + 'abbreviation', + 'shortDescription', + 'fullOutcomeDescription', + 'connectedOutcomes', + 'learningOutcomeAction', + ]; + public selectedOutcome: LearningOutcome; + public abbreviationPrefix: 'TLO' | 'ULO' | 'GLO'; + + public allOutcomes: LearningOutcome[] = []; + public selectedConnectedOutcomes = signal([]); + + private subscriptions: Subscription[] = []; + + constructor( + private alerts: AlertService, + private learningOutcomeService: LearningOutcomeService, + private fileDownloaderService: FileDownloaderService, + private nestedCsvDownloadModalService: NestedCsvDownloadModalService, + private feedbackTemplateService: FeedbackTemplateService, + private taskService: TaskService, + @Inject(csvResultModalService) private csvResultModalService: any, + @Inject(csvUploadModalService) private csvUploadModal: any, + @Inject(confirmationModal) private confirmationModal: any, + ) { + effect(() => { + const linkedOutcomes = this.selectedConnectedOutcomes().map((outcome) => outcome.id); + if ( + this.selectedOutcome && + !isEqual(linkedOutcomes.sort(), this.selectedOutcome.linkedOutcomeIds.sort()) + ) + this.selectedOutcome.linkedOutcomeIds = linkedOutcomes; + }); + } + + ngAfterViewInit(): void { + this.setAbbreviationPrefix(); + + if (!this.context) { + this.subscriptions.push( + this.learningOutcomeService.cache.values.subscribe((outcomes) => { + const glos = outcomes.filter((outcome) => outcome.contextType === null); + this.initialiseTable(glos); + }), + ); + return; + } + + this.subscriptions.push( + this.context.learningOutcomesCache.values.subscribe((learningOutcomes) => { + this.initialiseTable(learningOutcomes); + }), + ); + + this.subscriptions.push( + this.learningOutcomeService.cache.values.subscribe((outcomes) => { + const glos = outcomes.filter((outcome) => outcome.contextType === null); + this.allOutcomes = [...this.allOutcomes, ...glos]; + }), + ); + + if (this.context instanceof TaskDefinition) { + this.subscriptions.push( + this.context.unit.learningOutcomesCache.values.subscribe((learningOutcomes) => { + this.allOutcomes = [...this.allOutcomes, ...learningOutcomes]; + }), + ); + } + } + + ngOnChanges(changes: SimpleChanges): void { + this.setAbbreviationPrefix(); + + this.subscriptions.push( + this.context.learningOutcomesCache.values.subscribe((learningOutcomes) => { + this.initialiseTable(learningOutcomes); + }), + ); + + this.selectedOutcome = null; + } + + ngOnDestroy(): void { + this.subscriptions.forEach((s) => s.unsubscribe()); + } + + setAbbreviationPrefix(): void { + if (!this.context) this.abbreviationPrefix = 'GLO'; + else if (this.context instanceof TaskDefinition) this.abbreviationPrefix = 'TLO'; + else if (this.context instanceof Unit) this.abbreviationPrefix = 'ULO'; + } + + initialiseTable(learningOutcomes: LearningOutcome[]) { + this.outcomeSource = new MatTableDataSource(learningOutcomes); + this.outcomeSource.paginator = this.outcomePaginator; + this.outcomeSource.sort = this.outcomeSort; + this.outcomeSource.filterPredicate = (data: LearningOutcome, filter: string) => { + const filterValue = filter.trim().toLowerCase(); + return ( + data.abbreviation.toLowerCase().includes(filterValue) || + data.shortDescription.toLowerCase().includes(filterValue) || + data.fullOutcomeDescription.toLowerCase().includes(filterValue) + ); + }; + } + + public saveLearningOutcome(learningOutcome: LearningOutcome) { + if ( + !learningOutcome.abbreviation.trim() || + !learningOutcome.shortDescription.trim() || + !learningOutcome.fullOutcomeDescription.trim() + ) { + this.alerts.error('Failed to save learning outcome. Fill in required fields.'); + return; + } + learningOutcome.save().subscribe({ + next: () => { + this.alerts.success('Outcome saved'); + learningOutcome.setOriginalSaveData(this.learningOutcomeService.mapping); + this.selectLearningOutcome(this.selectedOutcome); + }, + error: () => this.alerts.error('Failed to save learning outcome. Please try again.'), + }); + } + + public selectLearningOutcome(learningOutcome: LearningOutcome) { + if (this.selectedOutcome === learningOutcome) { + this.selectedOutcome = null; + this.selectedConnectedOutcomes.update((_selectedConnectedOutcomes) => []); + } else { + this.selectedOutcome = learningOutcome; + this.selectedConnectedOutcomes.update(() => this.getLinkedOutcomes(learningOutcome)); + if (!this.selectedOutcome.context) this.selectedOutcome.context = this.context; + + if (!this.selectedOutcome.hasOriginalSaveData) { + this.selectedOutcome.setOriginalSaveData(this.learningOutcomeService.mapping); + } + } + } + + public sortOutcomeData(sort: Sort) { + const data = this.outcomeSource.data; + + if (!sort.active || sort.direction === '') { + this.outcomeSource.data = data; + return; + } + + this.outcomeSource.data = data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + switch (sort.active) { + case 'abbreviation': + return this.compare(a.abbreviation, b.abbreviation, isAsc); + case 'shortDescription': + return this.compare(a.shortDescription, b.shortDescription, isAsc); + case 'fullOutcomeDescription': + return this.compare(a.fullOutcomeDescription, b.fullOutcomeDescription, isAsc); + default: + return 0; + } + }); + } + + public compare(a: number | string, b: number | string, isAsc: boolean): number { + return (a < b ? -1 : 1) * (isAsc ? 1 : -1); + } + + applyFilter(filterValue: string) { + this.outcomeSource.filter = filterValue; + if (this.outcomeSource.paginator) { + this.outcomeSource.paginator.firstPage(); + } + } + + public learningOutcomeHasChanges(learningOutcome: LearningOutcome): boolean { + return learningOutcome.hasChanges(this.learningOutcomeService.mapping); + } + + public deleteLearningOutcome(learningOutcome: LearningOutcome) { + this.confirmationModal.show( + 'Delete learning outcome', + 'Are you sure you want to delete this outcome? This action is final.', + () => { + learningOutcome.delete().subscribe({ + next: () => { + this.alerts.success('Learning outcome deleted'); + if (this.selectedOutcome === learningOutcome) + this.selectLearningOutcome(this.selectedOutcome); + }, + error: () => this.alerts.error('Failed to delete learning outcome. Please try again.'), + }); + }, + ); + } + + public uploadCsv(type: 'Learning Outcomes' | 'Feedback Templates') { + let url: string; + + if (type === 'Learning Outcomes') url = this.context.getOutcomeBatchUploadUrl(); + else { + if (this.context) url = this.context.getFeedbackTemplateBatchUploadUrl(); + else url = `${API_URL}/global/feedback_chips/csv`; + } + + this.csvUploadModal.show( + `Upload ${type} as CSV`, + 'Test message', + {file: {name: `${type} CSV Data`, type: 'csv'}}, + url, + (response: any) => { + this.csvResultModalService.show(`${type} CSV Upload Results`, response); + if (response.success.length > 0) { + let contextType: 'units' | 'task_definitions'; + if (this.context instanceof Unit) { + this.context.refresh(); + contextType = 'units'; + } else if (this.context instanceof TaskDefinition) { + this.context.unit.refresh(); + contextType = 'task_definitions'; + } + if (type === 'Feedback Templates' && contextType) { + this.feedbackTemplateService + .fetchAll({contextType, contextId: this.context.id}, {}) + .subscribe({ + error: () => this.alerts.error('Error loading task feedback templates.'), + }); + } + } + }, + ); + } + + public downloadCsv(type: 'Learning Outcomes' | 'Feedback Templates') { + let url: string; + + if (type === 'Learning Outcomes') url = this.context.getOutcomeBatchUploadUrl(); + else { + if (this.context) url = this.context.getFeedbackTemplateBatchUploadUrl(); + else url = `${API_URL}/global/feedback_chips/csv`; + } + + let name = `${type}.csv`; + + if (this.context instanceof TaskDefinition) + name = `${this.context.unit.code}-${this.context.abbreviation}-${name}`; + else if (this.context instanceof Unit) name = `${this.context.code}-${name}`; + + if (this.context instanceof Unit) this.nestedCsvDownloadModalService.show(url, name, type); + else this.fileDownloaderService.downloadFile(url, name); + } + + public createLearningOutcome() { + const learningOutcome = new LearningOutcome(); + + if (this.context) { + learningOutcome.context = this.context; + if (this.context instanceof TaskDefinition) learningOutcome.contextType = 'TaskDefinition'; + else if (this.context instanceof Unit) learningOutcome.contextType = 'Unit'; + learningOutcome.contextId = this.context.id; + } + learningOutcome.abbreviation = this.abbreviationPrefix + String(this.getNextOutcomeNumber()); + learningOutcome.shortDescription = ''; + learningOutcome.fullOutcomeDescription = ''; + this.selectedConnectedOutcomes.update((_selectedConnectedOutcomes) => []); + + this.selectedOutcome = learningOutcome; + } + + readonly separatorKeysCodes: number[] = [ENTER, COMMA]; + readonly typedConnectedOutcome = model(''); + readonly filteredOutcomes = computed(() => { + const currentOutcome = this.typedConnectedOutcome().toLowerCase(); + return this.allOutcomes.filter((outcome) => { + const abbreviation = outcome.abbreviation?.toLowerCase(); + return ( + !this.selectedConnectedOutcomes().includes(outcome) && + (!currentOutcome || abbreviation?.includes(currentOutcome)) + ); + }); + }); + + readonly announcer = inject(LiveAnnouncer); + + add(event: MatChipInputEvent): void { + const value = (event.value || '').trim(); + + if (value) { + const outcome = this.allOutcomes.find( + (o) => o.abbreviation?.toLowerCase() === value.toLowerCase(), + ); + if (outcome && !this.selectedConnectedOutcomes().includes(outcome)) { + this.selectedConnectedOutcomes.update((selectedConnectedOutcomes) => [ + ...selectedConnectedOutcomes, + outcome, + ]); + } + } + + this.typedConnectedOutcome.set(''); + } + + remove(outcome: LearningOutcome): void { + this.selectedConnectedOutcomes.update((selectedConnectedOutcomes) => { + const updatedOutcomes = selectedConnectedOutcomes.filter( + (o) => o.abbreviation !== outcome.abbreviation, + ); + this.announcer.announce(`Removed ${outcome.abbreviation}`); + return updatedOutcomes; + }); + } + + select(event: MatAutocompleteSelectedEvent): void { + const outcome = this.allOutcomes.find( + (o) => o.abbreviation === event.option.viewValue.split(' - ')[0], + ); + + if (outcome && !this.selectedConnectedOutcomes().includes(outcome)) { + this.selectedConnectedOutcomes.update((selectedConnectedOutcomes) => [ + ...selectedConnectedOutcomes, + outcome, + ]); + } + + this.typedConnectedOutcome.set(''); + event.option.deselect(); + } + + getLinkedOutcomes(learningOutcome: LearningOutcome): LearningOutcome[] { + return this.allOutcomes.filter((outcome) => + learningOutcome.linkedOutcomeIds.includes(outcome.id), + ); + } + + getNextOutcomeNumber(): number { + if (this.outcomeSource.data && this.outcomeSource.data.length > 0) { + let abbr = this.outcomeSource.data[this.outcomeSource.data.length - 1].abbreviation; + abbr = abbr.replace(this.abbreviationPrefix, ''); + return Number(abbr) + 1; + } + return 1; + } +} diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html new file mode 100644 index 0000000000..db56ad8b3e --- /dev/null +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html @@ -0,0 +1,14 @@ +
+

Download the {{ data.type }} CSV

+
+

This action will download all {{ data.type.toLowerCase() }} associated with this unit.

+ Include task {{ data.type.toLowerCase() }} +
+
+ +
+ + +
diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts new file mode 100644 index 0000000000..508cf87af7 --- /dev/null +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts @@ -0,0 +1,25 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {FileDownloaderService} from '../../file-downloader/file-downloader.service'; + +@Component({ + selector: 'f-nested-csv-download-modal', + templateUrl: './nested-csv-download-modal.component.html', +}) +export class NestedCsvDownloadModalComponent { + public includeNested = false; + + constructor( + private fileDownloaderService: FileDownloaderService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: {url: string; name: string; type: string}, + ) {} + + downloadCsv() { + this.fileDownloaderService.downloadFile( + `${this.data.url}?includes_tlos=${this.includeNested}`, + this.data.name, + ); + this.dialogRef.close(); + } +} diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts new file mode 100644 index 0000000000..91e34ff400 --- /dev/null +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts @@ -0,0 +1,20 @@ +import {Injectable} from '@angular/core'; +import {MatDialogRef, MatDialog} from '@angular/material/dialog'; +import {NestedCsvDownloadModalComponent} from './nested-csv-download-modal.component'; + +@Injectable({ + providedIn: 'root', +}) +export class NestedCsvDownloadModalService { + constructor(public dialog: MatDialog) {} + + public show(url: string, name: string, type: string) { + const dialogRef: MatDialogRef = this.dialog.open( + NestedCsvDownloadModalComponent, + { + data: {url, name, type}, + width: '500px', + }, + ); + } +} diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.html b/src/app/common/modals/calendar-modal/calendar-modal.component.html index ad4bddd473..cdd72ca70b 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.html +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.html @@ -45,7 +45,7 @@

Web calendar

{{member.student.username || "N/A"}} {{member.student.name}} - + + + } + + +
+ @if (linkedUnit) { + {{ linkedUnit.code }} — {{ linkedUnit.name }} + @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') { +
+ + } + } @else { + This course has not yet been linked to an OnTrack Unit. + + @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') { +
+ + } @else { +
+ Only OnTrack staff are permitted to link this course. + } + } +
+ } + + diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.scss b/src/app/home/states/lti-dashboard/lti-dashboard.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts new file mode 100644 index 0000000000..0c0ad93d57 --- /dev/null +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts @@ -0,0 +1,217 @@ +import {AfterViewInit, Component, Inject, Input} from '@angular/core'; +import {StateService, UIRouter} from '@uirouter/angular'; +import {csvResultModalService} from 'src/app/ajs-upgraded-providers'; +import {ProjectService, User} from 'src/app/api/models/doubtfire-model'; +import {Unit} from 'src/app/api/models/unit'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {LtiService} from 'src/app/api/services/lti.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-lti-dashboard', + templateUrl: 'lti-dashboard.component.html', + styleUrls: ['lti-dashboard.component.scss'], +}) +export class LtiDashboardComponent implements AfterViewInit { + constructor( + @Inject(UIRouter) private router: UIRouter, + private ltiService: LtiService, + private userService: UserService, + private authenticationService: AuthenticationService, + private stateService: StateService, + private alertsService: AlertService, + private unitService: UnitService, + private projectService: ProjectService, + private confirmationModalService: ConfirmationModalService, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Inject(csvResultModalService) private _csvResultModalService: any, + private sidekiqProgressModalService: SidekiqProgressModalService, + ) {} + + @Input() ltik: string; + + // linkedUnit: UnitLink; + linkedUnit: Unit; + currentUser: User; + unauthorised: boolean = false; + + loadingState: 'creatingUser' | 'enrollingUser' | 'fetchingUnit'; + isLoading: boolean; + + isSyncingGrades: boolean; + isSyncingEnrolments: boolean; + + ngAfterViewInit(): void { + // Scroll to the bottom of the page in case the header is visible + // Ensures our action buttons are centered + setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 100); + + this.isLoading = true; + // TODO: add a spinner or loading indicator until final loading state is complete + + this.authenticationService.afterAuthCall(() => { + this.userService.currentUser.ltik = this.ltik; + this.currentUser = this.userService.currentUser; + + // Retrieve linked unit ID + this.ltiService.getUnitLink().subscribe({ + next: (link) => { + if (!link) { + console.log('no link, cant enrol'); + this.isLoading = false; + return; + } + + // this.getGrade(); + + // Ensure user is enrolled into the linked unit + this.ltiService.enrolUser(link).subscribe({ + next: () => { + // Fetch unit information + this.unitService.get(link.unitId).subscribe({ + next: (unit) => { + this.linkedUnit = unit; + this.isLoading = false; + }, + error: (error) => { + this.alertsService.error(error.error || error, 6000); + this.isLoading = false; + }, + }); + }, + error: (error) => { + console.error(error); + this.isLoading = false; + }, + }); + }, + error: (_error) => { + this.alertsService.error('Unauthorised. Please relaunch the app.', 6000); + this.unauthorised = true; + }, + }); + }); + } + + goToLinkUnit(): void { + this.stateService.go('lti/link', { + ltik: this.ltik, + }); + } + + removeLink(): void { + this.ltiService.removeUnitLink().subscribe({ + next: (link) => { + this.linkedUnit = null; + console.log(link); + }, + error: (error) => { + console.error(error); + this.alertsService.error(error.error, 6000); + }, + }); + } + + // getGrade(): void { + // this.ltiService.getGrade().subscribe({ + // next: (result) => { + // console.log('grade result?: ', result); + // console.log(JSON.stringify(result)); + // }, + // error: (error) => { + // console.log(error); + // }, + // }); + // } + + // syncMyGrade(): void { + // this.ltiService.syncGrade().subscribe({ + // next: (result) => { + // console.log('Successfully synced grade from OnTrack'); + // this.alertsService.success('Successfully synced grade from OnTrack', 5000); + // }, + // error: (error) => { + // console.log(error); + // this.alertsService.error(`Failed to retrieve grade`); + // }, + // }); + // } + + syncEnrolments(): void { + if (!this.linkedUnit) { + this.alertsService.error( + `Course must be linked to an OnTrack unit before you can sync members.`, + 6000, + ); + return; + } + + this.ltiService.getMembers().subscribe({ + next: (members) => { + this.confirmationModalService.show( + 'Sync Enrolments into OnTrack', + `Are you sure you want to import ${members.members.length} users into ${this.linkedUnit.code} ${this.linkedUnit.name}`, + () => { + this.isSyncingEnrolments = true; + this.ltiService.syncEnrolments().subscribe({ + next: (job) => { + if (!job) { + this.isSyncingEnrolments = false; + return this.alertsService.error(`Failed to sync enrolments`); + } + + this.sidekiqProgressModalService + .show('Syncing users into OnTrack', job.id) + .subscribe((completedJob) => { + this.isSyncingEnrolments = false; + this._csvResultModalService.show( + 'Enrolment sync', + JSON.parse(completedJob.result), + ); + this.alertsService.success('Successfully imported users into OnTrack', 5000); + }); + }, + error: (error) => { + console.log(error); + this.alertsService.error(`Failed to sync enrolments`); + this.isSyncingEnrolments = false; + }, + }); + }, + ); + }, + error: (_error) => { + this.alertsService.error('Failed to retrieve course members', 6000); + }, + }); + } + + syncStudentsGrades(): void { + this.confirmationModalService.show( + 'Sync Grades from OnTrack', + 'Are you sure you want to sync portfolio grades from OnTrack? Please confirm that grades are final and approved for release.', + () => { + this.isSyncingGrades = true; + this.ltiService.syncStudentsGrades().subscribe({ + next: (result) => { + this.isSyncingGrades = false; + this.alertsService.success('Successfully synced grades from OnTrack', 5000); + this._csvResultModalService.show('Grade sync', result); + }, + error: (error) => { + console.log(error); + this.alertsService.error(`Failed to retrieve grade`); + this.isSyncingGrades = true; + }, + }); + }, + ); + } + public launchApplication(): void { + window.open('http://localhost:4200/home', '_blank'); + } +} diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.html b/src/app/home/states/lti-unit-link/lti-unit-link.component.html new file mode 100644 index 0000000000..2ab7465ca9 --- /dev/null +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.html @@ -0,0 +1,46 @@ +
+
+
+ +

OnTrack

+
+ + @if (loadingUnits) { +

Loading...

+ } @else if (!activeUnits.length) { +

+ You must already be a Convenor or Admin to link a unit. You are not currently assigned to + any units. +

+ } @else { +

+ Students will be automatically enrolled in this unit when they launch the OnTrack tool from + this course. +

+ + Select a unit to link + + @for (unit of activeUnits; track unit) { + {{ unit.code }} {{ unit.name }} ({{ getTeachingPeriod(unit) }}) + } + + + + } +
+
diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.scss b/src/app/home/states/lti-unit-link/lti-unit-link.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.ts b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts new file mode 100644 index 0000000000..bb305a8ed3 --- /dev/null +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts @@ -0,0 +1,127 @@ +import {AfterViewInit, Component, Input} from '@angular/core'; +import {StateService} from '@uirouter/core'; +import {CreateNewUnitModal} from 'src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component'; +import {Unit} from 'src/app/api/models/unit'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {LtiService} from 'src/app/api/services/lti.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-lti-unit-link', + templateUrl: 'lti-unit-link.component.html', + styleUrls: ['lti-unit-link.component.scss'], +}) +export class LtiUnitLinkComponent implements AfterViewInit { + constructor( + private createUnitModalService: CreateNewUnitModal, + private unitService: UnitService, + private authenticationService: AuthenticationService, + private confirmationModalService: ConfirmationModalService, + private alertsService: AlertService, + private ltiService: LtiService, + private userService: UserService, + private stateService: StateService, + ) {} + + @Input() ltik: string; + + public selectedUnit: Unit; + public activeUnits: Unit[] = []; + + public unitLinked: boolean = false; + + public loadingUnits: boolean; + + ngAfterViewInit(): void { + this.loadingUnits = true; + + // Scroll to the bottom of the page in case the header is visible + // Ensures our action buttons are centered + setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 100); + + this.authenticationService.afterAuthCall(() => { + this.userService.currentUser.ltik = this.ltik; + this.loadUnits(); + }); + + // TODO: query our LTI API to see if we have already linked a unit + } + + public submit(): void { + this.confirmationModalService.show( + `Are you sure you want to link ${this.selectedUnit.code} ${this.selectedUnit.name} (${this.getTeachingPeriod(this.selectedUnit)}) to this course?`, + 'Once you have linked an OnTrack unit, students who launch this app will be enrolled automatically. Unlinking a unit will not withdraw students automatically.', + () => { + // Trigger API call to LTI.js with our unit link request + console.log('Trigger API call to LTI.js'); + this.linkUnit(this.selectedUnit); + }, + ); + } + + private formatTeachingPeriod(date): string { + const month = date.toLocaleString('en-US', {month: 'short'}); + const year = String(date.getFullYear()).slice(-2); + return `${month} '${year}`; + } + + public getTeachingPeriod(unit: Unit) { + if (unit.teachingPeriod?.name) { + return unit.teachingPeriod.name; + } + + return `${this.formatTeachingPeriod(unit.startDate)} - ${this.formatTeachingPeriod(unit.endDate)}`; + } + + private async linkUnit(unit: Unit) { + this.ltiService + .setUnitLink({ + unitId: unit.id.toString(), + // unitCode: unit.code, + // unitName: unit.name, + }) + .subscribe({ + next: (link) => { + console.log(link); + + this.alertsService.success(`Successfully linked ${unit.code}`, 5000); + + this.stateService.go('lti', { + ltik: this.ltik, + }); + }, + error: (error) => { + console.log(error); + this.alertsService.error(`Failed to link unit: ${error.error}`, 6000); + }, + }); + } + + public loadUnits(): void { + // Load units that current user is a convenor/admin of + this.unitService + .fetchAll( + {}, + { + params: { + include_in_active: true, + }, + }, + ) + .subscribe({ + next: (units) => { + // Show newer units first + this.activeUnits = [...units].sort( + (a, b) => b.startDate.getTime() - a.startDate.getTime(), + ); + this.loadingUnits = false; + }, + error: (error) => { + this.alertsService.error(`Failed to fetch units`, 6000); + }, + }); + } +} diff --git a/src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee b/src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee index 896a2eb2c7..3b45694da3 100644 --- a/src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee +++ b/src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module("doubtfire.projects.project-outcome-alignment", []) .directive("projectOutcomeAlignment", -> diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html index 5dc40dc5b0..4570c5fb1c 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html @@ -22,7 +22,7 @@

Target Grade

diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html index 53269a2a95..95a5664aaf 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html @@ -5,6 +5,11 @@

+
+
+ +
+
@@ -16,9 +21,26 @@

Target Grade

ng-model="project.targetGrade" ng-options="grade as grades.names[grade] for grade in grades.values" ng-if="$index != 4" - ng-change="updateTargetGrade(project.targetGrade)"> -
-
+ disabled + > + +
+ To change your target grade, use the + + Task Planner + +
+
+ +
+ +
+ +

Progress Burndown

diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html new file mode 100644 index 0000000000..da584e5670 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html @@ -0,0 +1,28 @@ + + + Plan Your Tasks + +

+ The Task Planner shows a timeline of your tasks, their due dates, and prerequisite + relationships. Use it to plan when to start and submit tasks, ensuring prerequisites are + completed early so you have time for feedback. +

+ @if (unit.allowFlexibleDates) { +

+ You can set your own start and target dates. Be mindful of each task’s + Feedback Deadline — submissions after this date will not be checked. Aim + to finish at least one week before the deadline, especially if you are targeting a higher + grade. +

+ } +
+
+ + + +
diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.scss b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts new file mode 100644 index 0000000000..3af5379eec --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts @@ -0,0 +1,14 @@ +import {Component, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; + +@Component({ + selector: 'f-task-planner-card', + templateUrl: './task-planner-card.component.html', + styleUrl: './task-planner-card.component.scss', +}) +export class TaskPlannerCardComponent { + @Input() project: Project; + public get unit() { + return this.project?.unit; + } +} diff --git a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.coffee b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.coffee index a504f3f1c6..b4212fa09b 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.coffee +++ b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.coffee @@ -44,7 +44,7 @@ angular.module('doubtfire.projects.states.dashboard.directives.student-task-list $scope.taskData.onSelectedTaskChange?(task) scrollToTaskInList(task) if task? scrollToTaskInList = (task) -> - taskEl = document.querySelector("student-task-list-#{task.taskKeyToIdString()}") + taskEl = document.querySelector("##{task.taskKeyToIdString()}") return unless taskEl? funcName = if taskEl.scrollIntoViewIfNeeded? then 'scrollIntoViewIfNeeded' else if taskEl.scrollIntoView? then 'scrollIntoView' return unless funcName? diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html new file mode 100644 index 0000000000..8cc634a7fd --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html @@ -0,0 +1,11 @@ +
+
+ comment +

Discussion Prompts for {{ project?.student?.name }}

+
+ + +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts new file mode 100644 index 0000000000..6156a4b191 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts @@ -0,0 +1,11 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'f-discussion-prompts-view', + templateUrl: './discussion-prompts-view.component.html', + styleUrls: ['./discussion-prompts-view.component.scss'], +}) +export class DiscussionPromptsViewComponent { + @Input() project; + @Input() taskDefinition; +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html new file mode 100644 index 0000000000..8b57557240 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html @@ -0,0 +1,8 @@ +
+
+ comment +

Staff Notes for {{ project?.student?.name }}

+
+ + +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts new file mode 100644 index 0000000000..45e4e76048 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts @@ -0,0 +1,10 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'f-staff-notes-view', + templateUrl: './staff-notes-view.component.html', + styleUrls: ['./staff-notes-view.component.scss'], +}) +export class StaffNotesViewComponent { + @Input() project; +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html index 5c7cc82d56..2e44b47ce8 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html @@ -7,20 +7,50 @@
+ @if (task) { + + }
  • {{ grades.names[taskDef?.targetGrade] }} Task
  • -
  • Start Date — Aim to start this task by {{ startDate() | date: 'EEE d MMM' }}.
  • -
  • - Extension — You have an extension for - {{ task?.extensions }} week{{ task?.extensions > 1 ? 's' : '' }}. -
  • -
  • Due Date — Aim to complete by {{ dueDate() | date: 'EEE d MMM' }}.
  • + + @if (taskDef.unit.allowFlexibleDates) { +
  • I'm planning to start this task by {{ startDate() | date: 'EEE d MMM' }}.
  • +
  • + The due date has been extended by {{ task?.extensions }} week{{ + task?.extensions > 1 ? 's' : '' + }}. +
  • +
  • I'm aiming to submit this task by {{ dueDate() | date: 'EEE d MMM' }}.
  • +
  • + To receive feedback, I must submit this task by + {{ feedbackDate() | date: 'EEE d MMM' }}. +
  • + } @else { +
  • + Start Date — I'm aiming to start this task by + {{ startDate() | date: 'EEE d MMM' }}. +
  • +
  • + Extension — The due date has been extended by + {{ task?.extensions }} week{{ task?.extensions > 1 ? 's' : '' }}. +
  • +
  • + Due Date — I'm aiming to submit this task by + {{ dueDate() | date: 'EEE d MMM' }}. +
  • + }
+ +
+ +
+ @if (isLoading) { +
+ +
+ } @else if (errorMessage) { +
+ {{ errorMessage }} +
+ } @else if (compareMode) { + @if (archiveBlob && comparedArchiveBlob) { +
+
+
+ + +
+ +
+ + @if (primaryArchiveParsed) { + + } @else { +
+ Loading archive... +
+ } +
+
+ +
+ @if (!bothSelectionsReady) { +
+ Select a file in both submissions to compare. +
+ } @else if (canShowDiffEditor) { +
+
+
+ {{ primarySelectedFile?.path ?? primarySelectedFile?.name }} +
+
+ {{ comparedSelectedFile?.path ?? comparedSelectedFile?.name }} +
+
+ +
+ } @else { +
+ + +
+ } +
+
+ } @else { +
+ Unable to load one or both submission archives. +
+ } + } @else if (archiveBlob) { +
+ + +
+ } @else { +
+ Unable to load submission files. +
+ } +
+ + +
+ Submission{{ number !== undefined ? ' ' + number : '' + }}{{ isMostRecent ? ' (Most recent)' : '' }}: + {{ timestamp | date: 'dd/MM/yyyy HH:mm' }} +
+
+ + +
+
+ + {{ file?.path ?? file?.name }} + + @if (selectedFilesMatch !== null) { + + {{ selectedFilesMatch ? 'Identical' : 'Different' }} + + } +
+ @if (isArchiveCodeOrTextFile(file)) { + + } @else if (isArchivePdfFile(file)) { + + } @else if (isArchiveImageFile(file)) { +
+ +
+ } @else { +
+ Preview not available for this file type. +
+ } +
+
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.scss new file mode 100644 index 0000000000..dd674872c8 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.scss @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + height: 100%; +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts new file mode 100644 index 0000000000..a0068a7cde --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts @@ -0,0 +1,279 @@ +import {HttpResponse} from '@angular/common/http'; +import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import * as monaco from 'monaco-editor'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {OverseerAssessment} from 'src/app/api/models/doubtfire-model'; +import { + ArchiveFileEntry, + isArchiveCodeOrTextFile, + isArchiveImageFile, + isArchivePdfFile, +} from 'src/app/common/archive-viewer/archive-viewer.helpers'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +export interface SubmissionFilesModalData { + assessment: OverseerAssessment; + assessmentNumber?: number; + assessmentIsMostRecent?: boolean; + comparedWith?: OverseerAssessment; + comparedWithNumber?: number; + comparedWithIsMostRecent?: boolean; +} + +@Component({ + selector: 'f-submission-files-modal', + templateUrl: './submission-files-modal.component.html', + styleUrls: ['./submission-files-modal.component.scss'], +}) +export class SubmissionFilesModalComponent implements OnInit, OnDestroy { + private readonly diffOriginalUri = monaco.Uri.parse('inmemory://submission-compare/original'); + private readonly diffModifiedUri = monaco.Uri.parse('inmemory://submission-compare/modified'); + public readonly isArchiveCodeOrTextFile = isArchiveCodeOrTextFile; + public readonly isArchiveImageFile = isArchiveImageFile; + public readonly isArchivePdfFile = isArchivePdfFile; + + public archiveBlob: Blob | null = null; + public comparedArchiveBlob: Blob | null = null; + public isLoading = true; + public uploadRequirementNames: string[] = []; + public errorMessage: string | null = null; + public primarySelectedFile: ArchiveFileEntry | null = null; + public comparedSelectedFile: ArchiveFileEntry | null = null; + public primaryArchiveParsed = false; + public comparedArchiveParsed = false; + public selectedFilesMatch: boolean | null = null; + private selectedFilesComparisonToken = 0; + + public diffEditorOptions = { + theme: 'vs', + language: 'plaintext', + renderMinimap: false, + readOnly: true, + domReadOnly: true, + renderMarginRevertIcon: false, + enableSplitViewResizing: false, + useInlineViewWhenSpaceIsLimited: false, + renderSideBySideInlineBreakpoint: 1000, + renderSideBySide: true, + compactMode: false, + minimap: { + enabled: false, + }, + lineNumbers: 'off', + automaticLayout: true, + }; + public singleEditorOptions = { + theme: 'vs', + language: 'plaintext', + automaticLayout: true, + scrollBeyondLastLine: false, + renderMinimap: false, + readOnly: true, + minimap: { + enabled: false, + }, + }; + public primarySingleEditorOptions = {...this.singleEditorOptions}; + public comparedSingleEditorOptions = {...this.singleEditorOptions}; + public diffOriginalModel: {language: string; code: string; uri: monaco.Uri} = { + language: 'plaintext', + code: '', + uri: this.diffOriginalUri, + }; + public diffModifiedModel: {language: string; code: string; uri: monaco.Uri} = { + language: 'plaintext', + code: '', + uri: this.diffModifiedUri, + }; + + constructor( + private fileDownloader: FileDownloaderService, + private alerts: AlertService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: SubmissionFilesModalData, + ) {} + + public get compareMode(): boolean { + return !!this.data.comparedWith; + } + + public get bothSelectionsReady(): boolean { + return !!this.primarySelectedFile && !!this.comparedSelectedFile; + } + + public get canShowDiffEditor(): boolean { + return ( + this.bothSelectionsReady && + isArchiveCodeOrTextFile(this.primarySelectedFile) && + isArchiveCodeOrTextFile(this.comparedSelectedFile) + ); + } + + ngOnInit(): void { + this.uploadRequirementNames = + this.data.assessment.task?.definition?.uploadRequirements?.map( + (requirement) => requirement?.name?.trim() ?? '', + ) ?? []; + + void this.loadSubmissionArchives(); + } + + ngOnDestroy(): void { + monaco.editor.getModel(this.diffOriginalUri)?.dispose(); + monaco.editor.getModel(this.diffModifiedUri)?.dispose(); + } + + private async loadSubmissionArchives(): Promise { + this.isLoading = true; + this.errorMessage = null; + this.primaryArchiveParsed = false; + this.comparedArchiveParsed = false; + this.primarySelectedFile = null; + this.comparedSelectedFile = null; + this.selectedFilesMatch = null; + this.resetDiffModels(); + this.resetSingleEditorOptions(); + + try { + if (this.data.comparedWith) { + this.archiveBlob = await this.downloadSubmissionArchive(this.data.assessment); + this.comparedArchiveBlob = await this.downloadSubmissionArchive(this.data.comparedWith); + } else { + this.archiveBlob = await this.downloadSubmissionArchive(this.data.assessment); + } + } catch (error) { + this.errorMessage = `Failed to load submission files: ${error}`; + this.alerts.error(this.errorMessage, 6000); + } finally { + this.isLoading = false; + } + } + + private downloadSubmissionArchive(assessment: OverseerAssessment): Promise { + return new Promise((resolve, reject) => { + this.fileDownloader.downloadBlob( + assessment.submissionFilesUrl(), + (_resourceUrl: string, response: HttpResponse) => { + if (!response.body) { + reject('No submission archive returned.'); + return; + } + resolve(response.body); + }, + (error) => { + reject(error?.error?.error ?? error); + }, + ); + }); + } + + public onPrimarySelectionChange(file: ArchiveFileEntry | null): void { + this.applySelectionChange(file, (value) => { + this.primarySelectedFile = value; + }); + } + + public onComparedSelectionChange(file: ArchiveFileEntry | null): void { + this.applySelectionChange(file, (value) => { + this.comparedSelectedFile = value; + }); + } + + private applySelectionChange( + file: ArchiveFileEntry | null, + assignSelection: (value: ArchiveFileEntry | null) => void, + ): void { + if (file && !file.isLoaded) { + return; + } + assignSelection(file); + this.refreshSingleEditorOptions(); + this.refreshDiffModels(); + void this.refreshSelectedFilesMatch(); + } + + public onPrimaryFilesLoaded(): void { + this.primaryArchiveParsed = true; + } + + public onComparedFilesLoaded(): void { + this.comparedArchiveParsed = true; + } + + private resetDiffModels(): void { + this.diffOriginalModel = {language: 'plaintext', code: '', uri: this.diffOriginalUri}; + this.diffModifiedModel = {language: 'plaintext', code: '', uri: this.diffModifiedUri}; + } + + private refreshDiffModels(): void { + if (!this.canShowDiffEditor) { + this.resetDiffModels(); + return; + } + + this.diffOriginalModel = { + language: this.primarySelectedFile?.language ?? 'plaintext', + code: this.primarySelectedFile?.textContent ?? '', + uri: this.diffOriginalUri, + }; + this.diffModifiedModel = { + language: this.comparedSelectedFile?.language ?? 'plaintext', + code: this.comparedSelectedFile?.textContent ?? '', + uri: this.diffModifiedUri, + }; + } + + private resetSingleEditorOptions(): void { + this.primarySingleEditorOptions = {...this.singleEditorOptions, language: 'plaintext'}; + this.comparedSingleEditorOptions = {...this.singleEditorOptions, language: 'plaintext'}; + } + + private refreshSingleEditorOptions(): void { + this.primarySingleEditorOptions = { + ...this.singleEditorOptions, + language: this.primarySelectedFile?.language ?? 'plaintext', + }; + this.comparedSingleEditorOptions = { + ...this.singleEditorOptions, + language: this.comparedSelectedFile?.language ?? 'plaintext', + }; + } + + private async refreshSelectedFilesMatch(): Promise { + const token = ++this.selectedFilesComparisonToken; + if (!this.primarySelectedFile || !this.comparedSelectedFile) { + this.selectedFilesMatch = null; + return; + } + + const [primaryHash, comparedHash] = await Promise.all([ + this.computeFileHash(this.primarySelectedFile), + this.computeFileHash(this.comparedSelectedFile), + ]); + + if (token !== this.selectedFilesComparisonToken) { + return; + } + + this.selectedFilesMatch = primaryHash === comparedHash; + } + + private async computeFileHash(file: ArchiveFileEntry): Promise { + let bytes: Uint8Array | null = file.data ?? null; + if (!bytes && file.textContent !== undefined) { + bytes = new TextEncoder().encode(file.textContent); + } + if (!bytes && file.blob) { + bytes = new Uint8Array(await file.blob.arrayBuffer()); + } + if (!bytes) { + return ''; + } + + const digest = await crypto.subtle.digest('SHA-256', bytes); + return Array.from(new Uint8Array(digest)) + .map((value) => value.toString(16).padStart(2, '0')) + .join(''); + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html new file mode 100644 index 0000000000..2773aed285 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html @@ -0,0 +1,207 @@ +
+ +
+ + @for (oa of overseerAssessments; track oa; let idx = $index) { + + + + + Submission {{ overseerAssessments.length - idx }}: {{ oa.timestamp | humanizedDate }} + @if (idx === 0) { + (Most recent) + } + @if (isComparisonSource(oa)) { + (Selected for comparison) + } + + @if (oa.reportReady) { +
+ {{ oa.passedSteps }} / {{ oa.totalSteps }} + @if (oa.passedSteps === oa.totalSteps) { + done + } @else { + cancel + } + @if (oa.hasSubmissionFiles && currentUnitRole) { + +
+ + + @if (hasComparisonSourceFor(oa)) { + + } @else if (isComparisonSource(oa)) { + + } @else { + + } + + } +
+ } @else { +
+ Tests In Progress + +
+ } +
+ + + @for (result of oa.stepResultsCache.values | async; track result.id; let idx = $index) { + + + + Step {{ idx + 1 }}: {{ result.overseerStep?.displayName }} + @if (result.pass) { + done + } @else { + cancel + } + + + + + + @if (!result.pass) { +

+ {{ result.feedbackMessage }} +

+ } + + @if ( + result.expectedOutput && + result.expectedOutput !== result.stdout && + (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) + ) { +
+ + + + + + +
+ @if (viewOutput === 'diff' || viewOutput === 'split_diff') { + @if (result.expectedOutput !== result.stdout) { + + } + } @else if (viewOutput === 'your_output') { + + } @else if (viewOutput === 'expected_output') { + + } + } @else if (result.stdout) { +
{{result.stdout}}
+ } @else if (result.pass) { +
SUCCESS
+
+ (No Output) +
+ } +
+ } + @if (loadingAssessments.has(oa.id)) { +
+ +
+ } @else { + @for (skipped of oa.stepsSkipped; track skipped.id; let idx = $index) { + + + + + + Step {{ oa.stepResultsCache.currentValues.length + idx + 1 }}: + {{ skipped?.displayName ?? '-' }} + (Skipped) + + + pause + + + } + } +
+
+ } @empty { +
+ subtitles_off +
No submission reports for this task.
+
+ } +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts new file mode 100644 index 0000000000..e576813299 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts @@ -0,0 +1,248 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {MatMenuTrigger} from '@angular/material/menu'; +import {OverseerAssessment, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; +import {Task} from 'src/app/api/models/task'; +import {OverseerAssessmentService} from 'src/app/api/services/overseer-assessment.service'; +import {OverseerStepResultService} from 'src/app/api/services/overseer-step-result.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; +import {SubmissionFilesModalComponent} from './submission-files-modal/submission-files-modal.component'; + +@Component({ + selector: 'f-task-overseer-report', + templateUrl: './task-overseer-report.component.html', + styleUrl: './task-overseer-report.component.scss', +}) +export class TaskOverseerReportComponent implements OnInit { + @Input() task: Task; + @Input() loadOverseerAssessmentId?: number; + public comparisonSourceAssessmentId: number | null = null; + + constructor( + private alerts: AlertService, + private submissions: TaskSubmissionService, + private overseerAssessmentService: OverseerAssessmentService, + private overseerStepResultsService: OverseerStepResultService, + private dialog: MatDialog, + private userService: UserService, + ) {} + + public get currentUnitRole(): UnitRole | undefined { + const currentUser = this.userService.currentUser; + return this.task.unit.staff.find((ur) => ur.user.id === currentUser.id); + } + + public viewOutput: 'your_output' | 'expected_output' | 'diff' | 'split_diff' = 'your_output'; + + stdoutOptions = { + theme: 'vs-dark', + language: 'plaintext', + renderMinimap: false, + lineNumbers: false, + + minimap: { + enabled: false, + }, + }; + editorOptions = { + theme: 'vs', + language: 'text', + renderMinimap: false, + minimap: { + enabled: false, + }, + readOnly: true, + }; + + diffEditorOptions = { + theme: 'vs', + language: 'plaintext', + renderMinimap: false, + readOnly: true, + domReadOnly: true, + renderMarginRevertIcon: false, + enableSplitViewResizing: false, + useInlineViewWhenSpaceIsLimited: false, + renderSideBySideInlineBreakpoint: 1000, + renderSideBySide: true, + compactMode: true, + minimap: { + enabled: false, + }, + lineNumbers: 'off', + }; + + diff() { + this.diffEditorOptions.renderSideBySide = false; + this.diffEditorOptions.compactMode = true; + this.diffEditorOptions = {...this.diffEditorOptions}; + this.viewOutput = 'diff'; + } + + splitDiff() { + this.diffEditorOptions.renderSideBySide = true; + this.diffEditorOptions.compactMode = false; + this.diffEditorOptions = {...this.diffEditorOptions}; + setTimeout(() => { + this.viewOutput = 'split_diff'; + }, 100); + } + + submissionOutput() { + this.viewOutput = 'your_output'; + } + + expectedOutput() { + this.viewOutput = 'expected_output'; + } + + public overseerAssessments: OverseerAssessment[] = []; + + public get comparisonSourceAssessment(): OverseerAssessment | null { + if (!this.comparisonSourceAssessmentId) { + return null; + } + return ( + this.overseerAssessments.find( + (assessment) => assessment.id === this.comparisonSourceAssessmentId, + ) ?? null + ); + } + + ngOnInit(): void { + this.loadAssessments(); + } + + loadAssessments(isRefresh: boolean = false) { + if (isRefresh) { + this.loadOverseerAssessmentId = null; + } + this.overseerAssessmentService.queryForTask(this.task).subscribe({ + next: (assessments) => { + this.overseerAssessments = assessments; + if ( + this.comparisonSourceAssessmentId && + !this.overseerAssessments.some( + (assessment) => assessment.id === this.comparisonSourceAssessmentId, + ) + ) { + this.comparisonSourceAssessmentId = null; + } + for (const oa of this.overseerAssessments) { + for (const result of oa.stepResultsCache.currentValues) { + result.overseerStep = this.task.definition.overseerStepsCache.currentValues.find( + (step) => step.id === result.overseerStepId, + ); + } + } + }, + error: (error) => { + this.alerts.error(`Failed to load overseer reports: ${error}`, 6000); + }, + }); + } + + loadingAssessments = new Set(); + + onAssessmentOpen(overseerAssesment: OverseerAssessment) { + if (this.loadOverseerAssessmentId === overseerAssesment.id) { + setTimeout(() => { + const el = document.getElementById(`oa-panel-${overseerAssesment.id}`); + el?.scrollIntoView({behavior: 'smooth', block: 'start'}); + }, 250); + } + + this.loadingAssessments.add(overseerAssesment.id); + + this.overseerStepResultsService.getOverseerStepResults(overseerAssesment).subscribe({ + next: () => { + for (const oa of this.overseerAssessments) { + for (const result of oa.stepResultsCache.currentValues) { + result.overseerStep = this.task.definition.overseerStepsCache.currentValues.find( + (step) => step.id === result.overseerStepId, + ); + } + } + this.loadingAssessments.delete(overseerAssesment.id); + }, + error: (error) => { + console.error(error); + this.loadingAssessments.delete(overseerAssesment.id); + }, + }); + } + + viewSubmissionOptions(event: Event) { + event.stopPropagation(); + } + + isComparisonSource(assessment: OverseerAssessment): boolean { + return this.comparisonSourceAssessmentId === assessment.id; + } + + hasComparisonSourceFor(assessment: OverseerAssessment): boolean { + return ( + this.comparisonSourceAssessmentId !== null && + this.comparisonSourceAssessmentId !== assessment.id + ); + } + + selectComparisonSource( + assessment: OverseerAssessment, + event?: Event, + menuTrigger?: MatMenuTrigger, + ) { + event?.stopPropagation(); + this.comparisonSourceAssessmentId = assessment.id; + menuTrigger?.closeMenu(); + this.alerts.message(`Selected submission ${assessment.timestampString} for comparison.`, 3500); + } + + clearComparisonSource(event?: Event) { + event?.stopPropagation(); + this.comparisonSourceAssessmentId = null; + } + + compareWithSelected(assessment: OverseerAssessment, event?: Event) { + event?.stopPropagation(); + const selected = this.comparisonSourceAssessment; + if (!selected || selected.id === assessment.id) { + return; + } + + this.openSubmissionFilesDialog(assessment, selected); + } + + viewSubmissionFiles(assessment: OverseerAssessment, event?: Event) { + event?.stopPropagation(); + this.openSubmissionFilesDialog(assessment); + } + + private openSubmissionFilesDialog( + assessment: OverseerAssessment, + comparedWith?: OverseerAssessment, + ) { + const assessmentIndex = this.overseerAssessments.findIndex((item) => item.id === assessment.id); + const comparedWithIndex = comparedWith + ? this.overseerAssessments.findIndex((item) => item.id === comparedWith.id) + : -1; + + this.dialog.open(SubmissionFilesModalComponent, { + data: { + assessment, + assessmentNumber: + assessmentIndex >= 0 ? this.overseerAssessments.length - assessmentIndex : undefined, + assessmentIsMostRecent: assessmentIndex === 0, + comparedWith, + comparedWithNumber: + comparedWithIndex >= 0 ? this.overseerAssessments.length - comparedWithIndex : undefined, + comparedWithIsMostRecent: comparedWithIndex === 0, + }, + maxWidth: '95vw', + width: '100%', + height: '90vh', + panelClass: 'submission-files-dialog', + }); + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html new file mode 100644 index 0000000000..686ec1d828 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html @@ -0,0 +1,16 @@ + +
+ Prerequisite Tasks + pending_actions +
+ + + You must meet the prerequisites for this task before submitting + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }}. + +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts new file mode 100644 index 0000000000..7bd7259574 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts @@ -0,0 +1,12 @@ +import {Component, Input} from '@angular/core'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Task} from 'src/app/api/models/task'; +@Component({ + selector: 'f-task-prerequisites-card', + templateUrl: './task-prerequisites-card.component.html', + styleUrls: ['./task-prerequisites-card.component.scss'], +}) +export class TaskPrerequisitesCardComponent { + @Input() taskDefinition: TaskDefinition; + @Input() task?: Task; +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html new file mode 100644 index 0000000000..d63cfbbd5c --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -0,0 +1,92 @@ +@if (isPassed) { + + @if (this.task.latestCompletedTestAttempt.scoreScaled === 1) { + + check + Knowledge Check Passed Without Mistakes + + } + @if (this.task.latestCompletedTestAttempt.scoreScaled !== 1) { + + check + Knowledge Check Passed + + } + +

+ You have successfully completed this knowledge check. You can now proceed to submitting task + files. +

+
+ + + +
+} +@if (!isPassed) { + + @if (isPassed === false) { + + close + Knowledge Check Unsuccessful + + } + @if (isPassed === undefined) { + + Knowledge Check + + } + +

You have to successfully pass this knowledge check to complete the task.

+

+ You have {{ attemptsLeft !== undefined ? attemptsLeft : 'unlimited' }} attempts left to + complete this test. +

+

+ There will be an increased time delay between test attempts. First 2 attempts will not have + a time delay in between. +

+
+ + + + + +
+} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts new file mode 100644 index 0000000000..53d0618d28 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -0,0 +1,63 @@ +import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {Task, User, UserService} from 'src/app/api/models/doubtfire-model'; +import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service'; + +@Component({ + selector: 'f-task-scorm-card', + templateUrl: './task-scorm-card.component.html', + styleUrls: ['./task-scorm-card.component.scss'], +}) +export class TaskScormCardComponent implements OnChanges { + @Input() task: Task; + attemptsLeft: number; + isPassed: boolean; + user: User; + + constructor( + private extensions: ScormExtensionModalService, + private userService: UserService, + ) { + this.user = this.userService.currentUser; + } + + ngOnChanges(changes: SimpleChanges) { + if (changes.task && changes.task.currentValue && changes.task.currentValue.scormEnabled) { + this.attemptsLeft = undefined; + this.isPassed = undefined; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + this.task?.fetchTestAttempts().subscribe((_) => { + this.getAttemptsLeft(); + if (this.task.latestCompletedTestAttempt) this.isPassed = this.task.scormPassed; + }); + } + } + + getAttemptsLeft(): void { + if (this.task.definition.scormAttemptLimit != 0) { + const attempts = this.task.testAttemptCache.currentValues; + let count = attempts.length; + if (count > 0 && attempts[0].terminated === false) count--; + this.attemptsLeft = + this.task.definition.scormAttemptLimit + this.task.scormExtensions - count; + } + } + + isNotStudent(): boolean { + return this.user !== this.task.project.student; + } + + launchScormPlayer(): void { + this.task.launchScormPlayer(); + } + + reviewLatestCompletedAttempt(): void { + this.task.latestCompletedTestAttempt.review(); + } + + requestExtraAttempt(): void { + this.extensions.show(this.task, () => { + this.task.refresh(); + }); + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html index f068cb609f..a7f0e0aed0 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html @@ -4,57 +4,90 @@

Similarities

- + @if (!jplagOpenState) { + + } + @if (jplagOpenState) { + + }
- - @for (similarity of task?.similarityCache.values | async; track similarity) { -

- @for (part of similarity.parts; track part; let i = $index) { - - - - {{ similarity.friendlyTypeName }} - - {{ part.description }} - @if (similarity.readyForViewer) { - - } - @if (i === 0) { - + + + @if (!jplagOpenState) { + + @for (similarity of task?.similarityCache.values | async; track similarity) { +

+ @for (part of similarity.parts; track part; let i = $index) { + + + + {{ similarity.friendlyTypeName }} + + {{ part.description }} + @if (similarity.readyForViewer) { + @if (similarity.type === 'JplagTaskSimilarity') { + + } @else { + + } + } + @if (i === 0) { + + } + + @if (part.panelOpenState) { + @if (part.format) { + @if (part.format === 'html' || part.format === 'pdf') { + + } @else if (part.format === 'jplag') { + + } + } @else { +

There is no local similarity file for this.

+ } } -
- @if (part.panelOpenState && part.format) { - - } @else { -

There is no local similarity file for this.

- } -
+ + } } - } -
+ + } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts index 2a6739207a..abdfcf3288 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts @@ -1,10 +1,13 @@ -import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; -import { MatAccordion } from '@angular/material/expansion'; -import { Task } from 'src/app/api/models/task'; -import { TaskSimilarity } from 'src/app/api/models/task-similarity'; -import { TaskSimilarityService } from 'src/app/api/services/task-similarity.service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { SelectedTaskService } from '../../../../selected-task.service'; +import {HttpResponse} from '@angular/common/http'; +import {Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; +import {MatAccordion} from '@angular/material/expansion'; +import {Task} from 'src/app/api/models/task'; +import {TaskSimilarity} from 'src/app/api/models/task-similarity'; +import {TaskSimilarityService} from 'src/app/api/services/task-similarity.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {JplagReportViewerComponent} from 'src/app/projects/states/jplag/jplag-report-viewer.component'; +import {SelectedTaskService} from '../../../../selected-task.service'; @Component({ selector: 'f-task-similarity-view', @@ -14,16 +17,20 @@ import { SelectedTaskService } from '../../../../selected-task.service'; export class TaskSimilarityViewComponent implements OnChanges { @Input() task: Task; @ViewChild(MatAccordion) accordion: MatAccordion; + @ViewChild('jplagViewer') jplagViewer!: JplagReportViewerComponent; panelOpenState = false; + jplagOpenState = false; constructor( private taskSimilarityService: TaskSimilarityService, private alertsService: AlertService, - private selectedTaskService: SelectedTaskService + private selectedTaskService: SelectedTaskService, + private fileDownloaderService: FileDownloaderService, ) {} ngOnChanges(changes: SimpleChanges) { if (changes.task && changes.task.currentValue && this.task?.id) { + this.jplagOpenState = false; // eslint-disable-next-line @typescript-eslint/no-unused-vars this.task?.fetchSimilarities().subscribe((_) => { console.log('similarities fetched'); @@ -35,7 +42,7 @@ export class TaskSimilarityViewComponent implements OnChanges { e.stopPropagation(); similarity.flagged = !similarity.flagged; this.taskSimilarityService - .update({ taskId: similarity.task.id, id: similarity.id }, { entity: similarity }) + .update({taskId: similarity.task.id, id: similarity.id}, {entity: similarity}) .subscribe((_) => { this.alertsService.success('Similarity flag updated'); similarity.task.similarityFlag = similarity.task.similarityCache.currentValues @@ -50,8 +57,38 @@ export class TaskSimilarityViewComponent implements OnChanges { openReport(e: Event, similarity: TaskSimilarity) { e.stopPropagation(); // Open similarity report in new tab - similarity.fetchSimilarityReportUrl().subscribe((url) => { - window.open(url, '_blank'); + similarity.fetchSimilarityReportUrl().subscribe({ + next: (url) => { + window.open(url, '_blank'); + }, + error: (err) => { + this.alertsService.error(`Error accessing TurnItIn: ${err}`); + }, }); } + + viewJplagReport(similarity: TaskSimilarity) { + // Students are identified by their username in JPlag reports (configured by API) + // In most cases, usernames are a combination of their first and last names + this.fileDownloaderService.downloadBlob( + this.task.definition.getJplagReportUrl(), + (_, response: HttpResponse) => { + // Open JPlag report viewer in embedded iframe + setTimeout(() => { + this.jplagViewer.uploadReport(response.body); + setTimeout(() => { + // Open comparison between the two students + this.jplagViewer.openComparison( + similarity.task.project.student.username, + similarity.otherStudent.username, + ); + this.jplagOpenState = true; + }, 100); + }, 100); + }, + (error) => { + console.error(error); + }, + ); + } } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html index e210890833..7b49a65daa 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html @@ -1,44 +1,74 @@ @if (triggers?.length > 0) { - - - - - -

{{ task?.statusLabel() }}

-
-
- @for (trigger of triggers; track trigger) { - - -
{{ trigger.label }}
-
- } -
-
- } @if (triggers?.length < 0) { - - - -
{{ task?.statusLabel() }}
-
-
+ + + + + +

{{ task?.statusLabel() }}

+
+
+ @for (trigger of triggers; track trigger) { + + +
{{ trigger.label }}
+
+ } +
+
+ } + @if (triggers?.length < 0) { + + + +
{{ task?.statusLabel() }}
+
+
}

{{ task?.statusHelp().reason }} {{ task?.statusHelp().action }}

+ @if (task?.blockedByPrerequisiteTasks()) { +

+ To submit this task, you must first complete all tasks that are listed as prerequisites. +

+ }
- @if ( task?.unit.currentUserIsStaff || task?.canApplyForExtension() || (task?.inSubmittedState() && - task?.requiresFileUpload()) ) { - - @if (task?.canApplyForExtension()) { - - } @if (task?.inSubmittedState() && task?.requiresFileUpload()) { - - } + +
+ + + @if (task?.canApplyForExtension()) { + + } + @if (task?.inSubmittedState() && task?.requiresFileUpload()) { + + } +
+ +
+ +
+ + + +
- }
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts index d33646b066..8738a0bffd 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts @@ -1,35 +1,47 @@ -import { AfterViewInit, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { UIRouter } from '@uirouter/core'; +import {AfterViewInit, Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {UIRouter} from '@uirouter/core'; import * as _ from 'lodash'; -import { Task } from 'src/app/api/models/task'; -import { TaskStatusEnum } from 'src/app/api/models/task-status'; -import { TaskService } from 'src/app/api/services/task.service'; -import { ExtensionModalService } from 'src/app/common/modals/extension-modal/extension-modal.service'; +import {Task} from 'src/app/api/models/task'; +import {TaskStatusEnum, TaskStatusUiData} from 'src/app/api/models/task-status'; +import {TaskService} from 'src/app/api/services/task.service'; +import {ExtensionModalService} from 'src/app/common/modals/extension-modal/extension-modal.service'; +import {QrModalService} from 'src/app/common/modals/qr-modal/qr-modal.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {SubmissionTypeModalService} from 'src/app/tasks/modals/submission-type-modal/submission-type-modal.service'; +import {Project} from 'src/app/api/models/project'; +import {UserService} from 'src/app/api/services/user.service'; +import {FeedbackAppealModalService} from 'src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service'; @Component({ selector: 'f-task-status-card', templateUrl: './task-status-card.component.html', styleUrls: ['./task-status-card.component.scss'], }) export class TaskStatusCardComponent implements OnChanges, AfterViewInit { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - triggers: any; + triggers: TaskStatusUiData[]; textCss: string; constructor( private extensions: ExtensionModalService, private taskService: TaskService, private router: UIRouter, + private qrModalService: QrModalService, + private doubtfireConstants: DoubtfireConstants, + private submissionTypeModalService: SubmissionTypeModalService, + private userService: UserService, + private feedbackAppealService: FeedbackAppealModalService, ) {} @Input() task: Task; taskStatusColor: string; + private project?: Project; + ngOnChanges(changes: SimpleChanges): void { if (changes.task) { this.task = changes.task.currentValue; this.reapplyTriggers(); this.taskStatusColor = this.taskService.statusColors.get(this.task.statusClass()); - + this.project = this.task.project; this.textCss = `::ng-deep f-task-status-card .mat-mdc-text-field-wrapper.mdc-text-field { background-color: #${this.taskStatusColor} !important; }`; @@ -43,27 +55,78 @@ export class TaskStatusCardComponent implements OnChanges, AfterViewInit { reapplyTriggers(): void { // if tutor is in queryParam if (this.router.globals.params.tutor != null) { - this.triggers = this.taskService.statusKeys.map(this.taskService.statusData); + this.triggers = this.taskService.statusKeys + .map((k) => this.taskService.statusData(k)) + .filter((trigger) => { + if (trigger.status !== 'complete') { + return true; + } + + return this.task.canMarkComplete || this.task.status === 'complete'; + }); } else { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const studentTriggers = _.map(this.taskService.switchableStates.student, this.taskService.statusData) as any; + const studentTriggers = _.map( + this.taskService.switchableStates.student as TaskStatusEnum[], + (k) => this.taskService.statusData(k), + ); const filteredStudentTriggers = this.task.filterFutureStates(studentTriggers); this.triggers = filteredStudentTriggers; + // Ensure the current task's status is in the list + if (!this.triggers.find((t) => t.status === this.task.status)) { + this.triggers.push(this.taskService.statusData(this.task.status)); + } } this.taskService.statusKeys; } + public isReadyForFeedback(): boolean { + return this.task.status === 'ready_for_feedback'; + } + + public isSubmittedForPortfolio(): boolean { + return this.task.status === 'assess_in_portfolio'; + } + triggerTransition(trigger: TaskStatusEnum): void { - this.task.triggerTransition(trigger); + if (trigger === 'complete' && !this.task.canMarkComplete) { + return; + } + + if (trigger === 'ready_for_feedback') { + this.uploadSubmission(); + } else { + this.task.triggerTransition(trigger); + } + } + + uploadSubmission(): void { + if (this.task.definition.assessInPortfolioOnly) { + this.submissionTypeModalService.show(this.task); + } else { + this.task.triggerTransition('ready_for_feedback'); + } } updateFilesInSubmission(): void { this.task.presentTaskSubmissionModal(this.task.status, true); } + openDiscussionQrCode(): void { + const hostName = this.doubtfireConstants.HOST_URL; + const url = `${hostName}/tutor-discussion?unitId=${this.task.unit.id}&username=${this.userService.currentUser.username}`; + this.qrModalService.show( + url, + 'Display this QR code during your class so your tutor can scan it to view your submissions and mark your tasks as complete.', + ); + } + applyForExtension(): void { this.extensions.show(this.task, () => { this.task.refresh(); }); } + + openFeedbackAppealModal(): void { + this.feedbackAppealService.show(this.task); + } } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html index ca9f850437..368d4b8343 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html @@ -11,10 +11,12 @@ You can choose to download your previous submission or the files you uploaded below.

-

- You uploaded this submission {{ task.submissionDate | humanizedDate }}. -

+ @if (submission?.isUploaded && task.submissionDate) { +

+ You uploaded this submission {{ task.submissionDate | date: 'dd/MM/yyyy' }}. +

+ }

If you feel there has been an error in your submission, you can request to regenerate your submission under the "Actions" dropdown menu. @@ -54,4 +56,4 @@ - + \ No newline at end of file diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts index 771b1ce53e..8c10c71c40 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts @@ -81,4 +81,4 @@ export class TaskSubmissionCardComponent implements OnChanges, OnInit { downloadSubmissionFiles(): void { this.fileDownloader.downloadFile(this.urls.files, `${this.task.definition.abbreviation}.zip`); } -} +} \ No newline at end of file diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.tpl.html index b4d417cc17..44c36541dc 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.tpl.html @@ -15,7 +15,7 @@

submission or the files you uploaded below.

- You uploaded this submission {{task.submissionDate | humanizedDate}}. + You uploaded this submission {{task.submissionDate | date: 'dd/MM/yyyy'}}.

If you feel there has been an error in your submission, you can request to diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html new file mode 100644 index 0000000000..71ea152187 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html @@ -0,0 +1,20 @@ +

+
+ comment +

Tutor Notes for {{ unitRole?.user?.name }}

+
+ @if (task) { +

+ {{ task.definition.abbreviation }} {{ task.definition.name }} ({{ + task.project.student.name + }}) +

+ } +

+ Notes left here are for staff-only discussion about the feedback given to the student. Use this + space to question, clarify, or discuss the tutor’s feedback. These notes are visible to + {{ unitRole?.user?.name }} and other convenors. +

+ + +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts new file mode 100644 index 0000000000..33ba1dd5a4 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts @@ -0,0 +1,18 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {UnitRole} from 'src/app/api/models/unit-role'; + +@Component({ + selector: 'f-tutor-notes-view', + templateUrl: './tutor-notes-view.component.html', + styleUrls: ['./tutor-notes-view.component.scss'], +}) +export class TutorNotesViewComponent implements OnInit { + @Input() task?; + @Input() unitRole: UnitRole; + + ngOnInit(): void { + if (this.task && !this.unitRole) { + this.unitRole = this.task.tutor; + } + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee index 62292ad919..a5d9df4511 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee @@ -10,15 +10,22 @@ angular.module('doubtfire.projects.states.dashboard.directives.task-dashboard', showFooter: '@?' showSubmission: '@?' controller: ($scope, $stateParams, listenerService, newTaskService, DoubtfireConstants, TaskAssessmentModal, fileDownloaderService) -> - $scope.overseerEnabled = DoubtfireConstants.IsOverseerEnabled + # $scope.overseerEnabled = DoubtfireConstants.IsOverseerEnabled $scope.overseerEnabled = () -> DoubtfireConstants.IsOverseerEnabled.value && $scope.task?.overseerEnabled + $scope.urls = { + taskSheetPdfUrl: null + taskSubmissionPdfUrl: null + taskSubmissionPdfAttachmentUrl: null + taskFilesUrl: null + } + # Is the current user a tutor? $scope.tutor = $stateParams.tutor # the ways in which the dashboard can be viewed - $scope.dashboardViews = ["details", "submission", "task"] + $scope.dashboardViews = ["details", "submission", "task", "similarities", "overseer"] # set the current dashboard view to details by default updateCurrentView = -> @@ -32,17 +39,21 @@ angular.module('doubtfire.projects.states.dashboard.directives.task-dashboard', # Cleanup listeners = listenerService.listenTo($scope) # Required changes when task changes - listeners.push $scope.$watch('task.id', -> + listeners.push $scope.$watch('task.definition.id', -> return unless $scope.task? + task = $scope.task # get the url for the task sheet and the submissions - $scope.urls = { - taskSheetPdfUrl: $scope.task.definition.getTaskPDFUrl() - taskSubmissionPdfUrl: $scope.task.submissionUrl() - taskSubmissionPdfAttachmentUrl: $scope.task.submissionUrl(true) - taskFilesUrl: $scope.task.submittedFilesUrl() - } - - updateCurrentView() + $scope.urls.taskSheetPdfUrl = task.definition.getTaskPDFUrl() + $scope.urls.taskSubmissionPdfUrl = task.submissionUrl() + $scope.urls.taskSubmissionPdfAttachmentUrl = task.submissionUrl(true) + $scope.urls.taskFilesUrl = task.submittedFilesUrl() + + if $scope.isCurrentView('task') && !task.definition.hasTaskSheet + # If the task sheet is not available, switch to details view + updateCurrentView() + else if $scope.isCurrentView('submission') && !task.hasPdf + # If the submission is not available, switch to details view + updateCurrentView() ) # Set the selected dashboard view @@ -75,5 +86,9 @@ angular.module('doubtfire.projects.states.dashboard.directives.task-dashboard', $scope.downloadSubmittedFiles = () -> fileDownloaderService.downloadFile($scope.urls.taskFilesUrl) + $scope.switchView = (view) -> + if view in $scope.dashboardViews + $scope.currentView = view + ) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index b2d723387c..931c569b6e 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -1,21 +1,44 @@
- + - + + + + + + + + + + + + + + + + + - + diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html index 0962ddd82a..45893297a0 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html @@ -2,12 +2,13 @@
{{task.definition.name}} - {{task.definition.name}} - + {{task.definition.name}} + @@ -42,9 +49,23 @@
+ + + + - @@ -55,6 +76,18 @@
+ +
+ + Warning: This task has {{task.definition.taskPrerequisitesCache.currentValues.length}} + prerequisite{{ task.definition.taskPrerequisitesCache.currentValues.length > 1 ? 's' : '' }} + that you still need to complete. You won’t be able to submit this task until all prerequisites + are met. +
+
@@ -63,6 +96,12 @@
+
+ +
+
+ +
diff --git a/src/app/projects/states/dashboard/selected-task.service.ts b/src/app/projects/states/dashboard/selected-task.service.ts index 6a6684c81c..94730262da 100644 --- a/src/app/projects/states/dashboard/selected-task.service.ts +++ b/src/app/projects/states/dashboard/selected-task.service.ts @@ -8,6 +8,10 @@ export enum DashboardViews { submission, task, similarity, + staff_notes, + tutor_notes, + discussion_prompts, + overseer, } @Injectable({ @@ -61,6 +65,22 @@ export class SelectedTaskService { this.currentView$.next(DashboardViews.similarity); } + public showStaffNotes() { + this.currentView$.next(DashboardViews.staff_notes); + } + + public showTutorNotes() { + this.currentView$.next(DashboardViews.tutor_notes); + } + + public showOverseerReports() { + this.currentView$.next(DashboardViews.overseer); + } + + public showDiscussionPrompts() { + this.currentView$.next(DashboardViews.discussion_prompts); + } + public showSubmission() { if (!this.task$.value) return; this.currentPdfUrl$.next(this.task$.value.submissionUrl(false)); diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html new file mode 100644 index 0000000000..5dcbbf84ff --- /dev/null +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html @@ -0,0 +1,21 @@ +
+ @for (prompt of discussionPrompts; track prompt) { + + +
+ {{ prompt.taskDefinition.abbreviation }} +
+
+ {{ prompt.content }} +
+
+ {{ prompt.priorityLabel }} +
+
+
+ } +
diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.scss b/src/app/projects/states/discussion-prompts/discussion-prompts.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts new file mode 100644 index 0000000000..2e384498af --- /dev/null +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts @@ -0,0 +1,50 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; +import {Project, TaskDefinition, UserService} from 'src/app/api/models/doubtfire-model'; +import {StaffNote} from 'src/app/api/models/staff-note'; +import {DiscussionPromptService} from 'src/app/api/services/discussion-prompt.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-discussion-prompts', + templateUrl: './discussion-prompts.component.html', + styleUrl: './discussion-prompts.component.scss', +}) +export class DiscussionPromptsComponent implements OnInit { + @ViewChild('staffNotesContainer') staffNotesContainer!: ElementRef; + @ViewChild('staffNoteEditor', {static: false}) staffNoteEditor!: ElementRef; + + @Input() project: Project; + @Input() taskDefinition: TaskDefinition; + + loadingStaffNotes: boolean = true; + + noteText: string = ''; + + editingNote?: StaffNote; + editingNoteText?: string = ''; + + replyingToNote?: StaffNote; + + hoveredNoteId: number | null = null; + + discussionPrompts: DiscussionPrompt[] = []; + + constructor( + private userService: UserService, + private discussionPromptService: DiscussionPromptService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + ) {} + ngOnInit(): void { + console.log('task def?', this.taskDefinition); + this.loadingStaffNotes = true; + this.discussionPromptService + .loadDiscussionPromptsForPoject(this.project) + .subscribe((prompts) => { + console.log(prompts); + this.discussionPrompts = prompts; + }); + } +} diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index bb730a37c8..6d3cdb12d2 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -5,6 +5,7 @@ import {EntityCache} from 'ngx-entity-service'; import {BehaviorSubject, Observable, Subject, skip, take} from 'rxjs'; import { CampusService, + LearningOutcomeService, Project, ProjectService, TeachingPeriodService, @@ -16,6 +17,7 @@ import { } from 'src/app/api/models/doubtfire-model'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; /** * The different types of views that can be shown. Used by the header to determine details to show. @@ -106,6 +108,8 @@ export class GlobalStateService implements OnDestroy { private projectService: ProjectService, private campusService: CampusService, private teachingPeriodService: TeachingPeriodService, + private learningOutcomeService: LearningOutcomeService, + private feedbackTemplateService: FeedbackTemplateService, @Inject(UIRouter) private router: UIRouter, private alerts: AlertService, private mediaObserver: MediaObserver, @@ -114,17 +118,23 @@ export class GlobalStateService implements OnDestroy { this.loadedUnits = this.unitService.cache; this.currentUserProjects = this.projectService.cache; - this.authenticationService.checkUserCookie(); - + // Use timeout to ensure everything is loaded before we try to login setTimeout(() => { - if (this.authenticationService.isAuthenticated()) { - this.loadGlobals(); - } else { - // not loading anything as no user - just redirect to sign in - this.isLoadingSubject.next(false); - this.router.stateService.go('sign_in'); - } - }, 800); + // Try to login using the refresh token + this.authenticationService.attemptLoginUsingRefreshToken((result: boolean) => { + if (result) { + this.loadGlobals(); + } else { + // Loading is finshed... + this.isLoadingSubject.next(false); + + // and if we are not going to the sign in page, then redirect to it + if (this.router.globals.current.name !== 'sign_in') { + this.router.stateService.go('sign_in'); + } + } + }); + }, 100); // this is a hack to workaround horrific IOS "feature" // https://stackoverflow.com/questions/37112218/css3-100vh-not-constant-in-mobile-browser @@ -201,9 +211,8 @@ export class GlobalStateService implements OnDestroy { this.isLoadingSubject.next(true); this.userService.cache.clear(); this.clearUnitsAndProjects(); - this.authenticationService.signOut(); this.isLoadingSubject.next(false); - this.router.stateService.go('sign_in'); + this.authenticationService.signOut(); } public ngOnDestroy(): void { @@ -213,13 +222,14 @@ export class GlobalStateService implements OnDestroy { } public loadGlobals(): void { + // Indicate we are loading data... this.isLoadingSubject.next(true); // Loading observer watches for loading of campuses, and teaching periods before loading unit roles, and projects const loadingObserver = new Observable((subscriber) => { // Loading campuses this.campusService.query().subscribe({ - next: (_reponse) => { + next: (_response) => { subscriber.next(true); }, error: (_response) => { @@ -227,6 +237,33 @@ export class GlobalStateService implements OnDestroy { }, }); + if (this.userService.currentUser.isStaff) { + this.learningOutcomeService + .query({}, {endpointFormat: LearningOutcomeService.globalEndpoint}) + .subscribe({ + next: (_response) => { + subscriber.next(true); + }, + error: (_response) => { + this.alerts.error('Unable to access service. Failed loading GLOs.', 6000); + }, + }); + + this.feedbackTemplateService + .query({}, {endpointFormat: FeedbackTemplateService.globalEndpoint}) + .subscribe({ + next: (_response) => { + subscriber.next(true); + }, + error: (_response) => { + this.alerts.error( + 'Unable to access service. Failed loading GLO feedback templates.', + 6000, + ); + }, + }); + } + // Loading teaching periods this.teachingPeriodService.query().subscribe({ next: (_response) => { @@ -251,7 +288,6 @@ export class GlobalStateService implements OnDestroy { * Query the API for the units taught and studied by the current user. */ private loadUnitsAndProjects() { - this.isLoadingSubject.next(true); this.unitRoleService.query().subscribe({ next: (_unitRoles: UnitRole[]) => { // unit roles are now in the cache @@ -264,8 +300,14 @@ export class GlobalStateService implements OnDestroy { this.isLoadingSubject.next(false); }, 800); }, + error: (_response) => { + this.alerts.error('Unable to access the units you study.', 6000); + }, }); }, + error: (_response) => { + this.alerts.error('Unable to access your units.', 6000); + }, }); } diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.html b/src/app/projects/states/jplag/jplag-report-viewer.component.html new file mode 100644 index 0000000000..c5c52c229e --- /dev/null +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.html @@ -0,0 +1,9 @@ + diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.ts b/src/app/projects/states/jplag/jplag-report-viewer.component.ts new file mode 100644 index 0000000000..4021eb6d22 --- /dev/null +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.ts @@ -0,0 +1,74 @@ +import {Component, ElementRef, Input, ViewChild} from '@angular/core'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-jplag-report-viewer', + templateUrl: './jplag-report-viewer.component.html', +}) +export class JplagReportViewerComponent { + @ViewChild('jplagIframe', {static: true}) jplagIframe!: ElementRef; + + @Input() hidden: boolean = false; + + constructor(private alertService: AlertService) {} + + public uploadReport(file: Blob) { + const blobUrl = URL.createObjectURL(file); + this.jplagIframe.nativeElement.src = `/JPlag/?file=${encodeURIComponent(blobUrl)}`; + } + + public openComparison(firstSubmissionId: string, secondSubmissionId: string) { + const iframe = this.jplagIframe.nativeElement; + + const findLink = (doc: Document) => + (doc.querySelector( + `a[href="/JPlag/comparison/${firstSubmissionId}/${secondSubmissionId}"]`, + ) || + doc.querySelector( + `a[href="/JPlag/comparison/${secondSubmissionId}/${firstSubmissionId}"]`, + )) as HTMLElement | null; + + // If the Vue component isn't rendered yet, try to scroll down the window until we find it + const getScroller = (doc: Document) => { + const wrapper = doc.querySelector( + '.vue-recycle-scroller__item-wrapper', + ) as HTMLElement | null; + if (!wrapper) return null; + + let cur = wrapper.parentElement as HTMLElement | null; + while (cur) { + const overflowY = getComputedStyle(cur).overflowY; + if ( + (overflowY === 'auto' || overflowY === 'scroll') && + cur.scrollHeight > cur.clientHeight + ) { + return cur; + } + cur = cur.parentElement; + } + + return doc.scrollingElement as HTMLElement | null; + }; + + let elapsed = 0; + const interval = setInterval(() => { + const doc = iframe.contentDocument; + if (!doc) return; + + const el = findLink(doc); + if (el) { + el.click(); + clearInterval(interval); + return; + } + + getScroller(doc)?.scrollBy(0, 600); + + elapsed += 50; + if (elapsed >= 5000) { + clearInterval(interval); + this.alertService.error('Could not open JPlag comparison.', 6000); + } + }, 50); + } +} diff --git a/src/app/projects/states/outcomes/outcomes.coffee b/src/app/projects/states/outcomes/outcomes.coffee index 5c5d610928..d92214d086 100644 --- a/src/app/projects/states/outcomes/outcomes.coffee +++ b/src/app/projects/states/outcomes/outcomes.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.projects.states.outcomes', []) # diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html new file mode 100644 index 0000000000..553a823f91 --- /dev/null +++ b/src/app/projects/states/plan/project-plan.component.html @@ -0,0 +1,34 @@ +
+

Task Planner

+

+ @if (unit.allowFlexibleDates) { + View and adjust the due dates for your tasks. Remember to leave time to get and respond to + feedback. + } @else { + View the task deadlines for your project, so you can organise your work and ensure you meet + all submission requirements on time. + } +

+

+ Click on a task in the timeline to see how it connects to other tasks. This will show you which + tasks must be completed before it, and which tasks depend on it being completed first. +

+
+ +
+
+ + Target Grade + + @for (grade of gradeValues; track grade) { + {{ gradeString(grade) }} + } + + +
+ +
diff --git a/src/app/projects/states/plan/project-plan.component.scss b/src/app/projects/states/plan/project-plan.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/plan/project-plan.component.ts b/src/app/projects/states/plan/project-plan.component.ts new file mode 100644 index 0000000000..b405fccfed --- /dev/null +++ b/src/app/projects/states/plan/project-plan.component.ts @@ -0,0 +1,71 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatSelectChange} from '@angular/material/select'; +import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; +import {GlobalStateService} from '../index/global-state.service'; +import {TaskPlannerComponent} from './task-planner/task-planner.component'; + +@Component({ + selector: 'f-project-plan', + templateUrl: 'project-plan.component.html', + styleUrls: ['project-plan.component.scss'], +}) +export class ProjectPlanComponent implements OnInit { + public project: Project; + + @ViewChild(TaskPlannerComponent) planner!: TaskPlannerComponent; + + public get unit() { + return this.project?.unit; + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + public get gradeAcronyms() { + return this.gradeService.gradeAcronyms; + } + + public gradeString(grade: number) { + return this.gradeService.grades[grade]; + } + + constructor( + private globalStateService: GlobalStateService, + private gradeService: GradeService, + private projectService: ProjectService, + private alertService: AlertService, + ) { + this.globalStateService.currentViewAndEntitySubject$.subscribe((viewAndEntity) => { + if (viewAndEntity.viewType === 'PROJECT' && viewAndEntity.entity) { + this.project = viewAndEntity.entity as Project; + } + }); + } + + public selectedTargetGrade: number; + + ngOnInit(): void { + this.selectedTargetGrade = this.project.targetGrade; + } + + onTargetGradeChange(event: MatSelectChange) { + const previousTargetGrade = this.project.targetGrade; + this.project.targetGrade = event.value; + + this.projectService.update(this.project).subscribe({ + next: () => { + this.alertService.success(`Succesfully updated target grade`, 2000); + this.planner.refreshItems(false); + }, + error: (error) => { + this.project.targetGrade = previousTargetGrade; + this.selectedTargetGrade = previousTargetGrade; + this.alertService.error(`Failed to update target grade: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html new file mode 100644 index 0000000000..5ea71774fd --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html @@ -0,0 +1,79 @@ + + + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + + + + + Task Description: +

{{ taskDefinition.description }}

+ + @if (!task.hasPrerequisiteTasks()) { +
This task has no prerequisites.
+ } + + @if (dependents.length) { + + + Required by + + + + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} is a + prerequisite for the following tasks. In some cases, + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} needs to + reach the Discuss or Complete status, which requires + tutor feedback. Plan ahead to avoid being locked out of submission. + + + + + + + + + + + + + + + + + + +
Task + {{ link.taskDefinition?.abbreviation }} {{ link.taskDefinition?.name }} + Submission Open + @if (link.taskDefinition.projectTask(project).blockedByPrerequisiteTasks()) { + block_outlined + } @else { + check_circle + } + + Required Status + +
+
+
+ } @else { +
+ This task is not a prerequisite for any other tasks. +
+ } +
+
diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.scss b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts new file mode 100644 index 0000000000..54f2aaadf0 --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts @@ -0,0 +1,39 @@ +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatTableDataSource} from '@angular/material/table'; +import {Project} from 'src/app/api/models/project'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; + +export interface TaskPlannerPrerequisitesModalData { + taskDefinition: TaskDefinition; + project: Project; + dependents: TaskPrerequisite[]; +} + +@Component({ + selector: 'f-task-planner-prerequisites-modal', + templateUrl: './task-planner-prerequisites-modal.component.html', + styleUrl: './task-planner-prerequisites-modal.component.scss', +}) +export class TaskPlannerPrerequisitesModalComponent implements OnInit { + @Input() taskDefinition: TaskDefinition; + @Input() project: Project; + @Input() dependents: TaskPrerequisite[]; + + public dataSource = new MatTableDataSource(); + public displayedColumns: string[] = ['task-definition', 'current-status', 'required-status']; + + public get task() { + return this.project?.findTaskForDefinition(this.taskDefinition?.id); + } + + constructor(@Inject(MAT_DIALOG_DATA) public data: TaskPlannerPrerequisitesModalData) {} + + ngOnInit(): void { + this.taskDefinition = this.data.taskDefinition; + this.project = this.data.project; + this.dependents = this.data.dependents; + this.dataSource.data = this.dependents; + } +} diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts new file mode 100644 index 0000000000..4f12f4fd1f --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts @@ -0,0 +1,27 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import { + TaskPlannerPrerequisitesModalComponent, + TaskPlannerPrerequisitesModalData, +} from './task-planner-prerequisites-modal.component'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; + +@Injectable({ + providedIn: 'root', +}) +export class TaskPlannerPrerequisitesModalService { + constructor(public dialog: MatDialog) {} + + public show(project: Project, taskDefinition: TaskDefinition, dependents: TaskPrerequisite[]) { + this.dialog.open( + TaskPlannerPrerequisitesModalComponent, + { + data: {taskDefinition, project, dependents}, + width: '100%', + maxWidth: '900px', + panelClass: 'overflow-y-auto', + }, + ); + } +} diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.html b/src/app/projects/states/plan/task-planner/task-planner.component.html new file mode 100644 index 0000000000..025da92aa5 --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.html @@ -0,0 +1,129 @@ +
+
+ Show Task Dates +
+ @if (unit.allowFlexibleDates) { +
+ + +
+ } +
+ + + + +
+
+ +
+ {{ item.title }} +
+
+ +
+
+
+ + @if (showDatesColumn) { + + + {{ toDateString(item.start) }} + + + + + + {{ toDateString(item.end) }} + + + + + + {{ item.task.localDeadlineDate() ? toDateString(item.task.localDeadlineDate()) : 'N/A' }} + + + } + + +
+
+ @if (unsavedChanges(item)) { + change_circle + } + @if (prerequisiteConflict(item)) { + warning + } @else if (isBlockedByPrerequisite(item)) { + warning + } + @if (isPastFeedbackDeadline(item)) { + dangerous + } + @if (isCloseToFeedbackDeadline(item)) { + query_builder + } +
+ +   {{ item.title }} +
+
+
+
+
diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.scss b/src/app/projects/states/plan/task-planner/task-planner.component.scss new file mode 100644 index 0000000000..ddf668e57b --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.scss @@ -0,0 +1,18 @@ +:host ::ng-deep .flexible-dates .gantt-links-overlay svg { + z-index: 999 !important; + pointer-events: none; +} + +:host ::ng-deep .flexible-dates .gantt-links-overlay-main { + height: 1px; + overflow: visible !important; + pointer-events: none; +} + +.gantt-bar { + background-color: var(--bar-bg); +} + +.flash { + transition: background-color 500ms ease-in-out; +} diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.ts b/src/app/projects/states/plan/task-planner/task-planner.component.ts new file mode 100644 index 0000000000..44574d803f --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.ts @@ -0,0 +1,613 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {UIRouter} from '@uirouter/core'; +import { + GanttBaselineItem, + GanttDate, + GanttItem, + GanttLink, + GanttLinkType, + GanttViewOptions, + GanttViewType, + NgxGanttComponent, +} from '@worktile/gantt'; +import {Project} from 'src/app/api/models/project'; +import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; +import {TaskPlannerPrerequisitesModalService} from './task-planner-prerequisites-modal/task-planner-prerequisites-modal.service'; + +interface TaskGanttItem extends GanttItem { + highlighted?: boolean; + taskDefinition: TaskDefinition; + task: Task; + originalLinks: GanttLink[]; +} + +@Component({ + selector: 'f-task-planner', + templateUrl: './task-planner.component.html', + styleUrl: './task-planner.component.scss', +}) +export class TaskPlannerComponent implements OnInit { + // Show a warning if the task's target end date is within this many days of the feedback deadline + public readonly CLOSE_TO_FEEDBACK_DEADLINE_THRESHOLD = 7; + + @Input() project: Project; + @Input() targetGrade: number; + + @ViewChild('gantt') ganttComponent: NgxGanttComponent; + + public viewType: GanttViewType = GanttViewType.day; + public viewOptions: GanttViewOptions; + + public allTaskPrerequisites: TaskPrerequisite[]; + public taskPrerequisites: TaskPrerequisite[]; + + public items: TaskGanttItem[] = []; + + // TaskDefinition default dates for reference + public baselineItems: GanttBaselineItem[] = []; + + public animateBackground: boolean = false; + public showDatesColumn: boolean = false; + public overlayLines: boolean = false; + + public get unit() { + return this.project?.unit; + } + + constructor( + private gradeService: GradeService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + private taskPlannerPrerequisitesModal: TaskPlannerPrerequisitesModalService, + private taskPrerequisiteService: TaskPrerequisiteService, + private router: UIRouter, + ) {} + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + public get gradeAcronyms() { + return this.gradeService.gradeAcronyms; + } + + public gradeString(grade: number) { + return this.gradeService.grades[grade]; + } + + onBarHover(item: TaskGanttItem) { + this.setLinkColors(item, true); + } + + onBarLeave(item: TaskGanttItem) { + this.setLinkColors(item, false); + } + + setLinkColors(item: TaskGanttItem, active: boolean) { + this.overlayLines = active; + + const ganttItem = this.items.find((i) => i.id === item.id); + ganttItem.links.forEach((linkItem) => { + const link = linkItem as GanttLink; + this.toggleLinkOpacity(link, active); + }); + + const prerequisites = this.items.filter((i) => { + const links = i.links; + if (typeof links === 'string') { + return false; + } + + return links.some((l) => typeof l !== 'string' && l.link === item.id); + }); + + prerequisites.forEach((prereq) => { + prereq.links.forEach((linkItem) => { + const link = linkItem as GanttLink; + if (link.link == item.id) { + this.toggleLinkOpacity(link, active); + } + }); + }); + + this.items = [...this.items]; + } + + private toggleLinkOpacity(link: GanttLink, active: boolean) { + const color = link.color as {active: string; default: string}; + + if (!active && !color.default.endsWith('0.1)')) { + // Dim link by lowering alpha + color.default = color.default.slice(0, -2) + '0.1)'; + } else if (active && color.default.endsWith('0.1)')) { + // Restore full opacity + color.default = color.default.slice(0, -4) + '1)'; + } + } + + barClick(item: TaskGanttItem) { + const td = item.taskDefinition; + const prereqs = this.taskPrerequisites.filter((p) => p.prerequisiteId === td.id); + this.taskPlannerPrerequisitesModal.show(this.project, td, prereqs); + } + + private mapPrerequisites() { + for (const prerequisite of this.allTaskPrerequisites) { + prerequisite.taskDefinition = this.unit.taskDefinitions.find( + (td) => td.id === prerequisite.taskDefinitionId, + ); + prerequisite.prerequisite = this.unit.taskDefinitions.find( + (td) => td.id === prerequisite.prerequisiteId, + ); + } + this.allTaskPrerequisites = [...this.allTaskPrerequisites]; + } + + public blockedDependents: Map = new Map(); + + // Check to see if this task is a prerequisite for another task + // If it is, ensure the end date on the task is before the start of its dependent task + prerequisiteConflict(item: TaskGanttItem) { + if (!item.links.length) { + return false; + } + + let isAfterDependentStartDate: boolean = false; + for (const ganttLink of item.links) { + if (typeof ganttLink === 'string') { + continue; + } + + const ganttItem = this.items.find((i) => i.id === ganttLink.link); + if (!ganttItem) { + return false; + } + const diff = this.normalizeDateUTC(item.end) - this.normalizeDateUTC(ganttItem.end); + const color = typeof ganttLink.color === 'string' ? ganttLink.color : ganttLink.color.default; + + if (diff > 0) { + isAfterDependentStartDate = true; + } + + continue; + + if (color === '#0079D8') { + // Ready for feedback + if (diff > 0) { + isAfterDependentStartDate = true; + } + } else if (color === '#31b0d5' || color === '#5BB75B') { + // Discuss or Complete + if (diff >= -7 * 24 * 60 * 60) { + // We need to ensure this task is submitted a week earlier than its dependent so get it in a Discuss state + isAfterDependentStartDate = true; + } + } + } + + return isAfterDependentStartDate; + } + + isBlockedByPrerequisite(item: TaskGanttItem) { + const prerequisites = this.items.filter((i) => { + const links = i.links; + if (typeof links === 'string') { + return false; + } + + return links.some((l) => typeof l !== 'string' && l.link === item.id); + }); + + for (const link of prerequisites) { + if (this.prerequisiteConflict(link)) { + const diff = this.normalizeDateUTC(link.end) - this.normalizeDateUTC(item.end); + if (diff > 0) { + return true; + } + } + } + + return false; + } + + getItemClasses(item: TaskGanttItem): string[] { + const classes: string[] = ['gantt-bar']; + if (this.animateBackground) { + classes.push('flash'); + } + if (item.highlighted) { + classes.push('[--bar-bg:#03c6fc]'); + } else if (this.isPastFeedbackDeadline(item)) { + classes.push('[--bar-bg:#cd3704]', 'text-white'); + } else if (this.isBlockedByPrerequisite(item)) { + classes.push('[--bar-bg:#e88307]', 'text-black'); + } else if (this.isCloseToFeedbackDeadline(item)) { + classes.push('[--bar-bg:#ffc53d]', 'text-black'); + } else { + classes.push('[--bar-bg:#0e467b]', 'text-white'); + } + + return classes; + } + + isPastFeedbackDeadline(item: TaskGanttItem) { + return item.end > item.task.localDeadlineDate().getTime() / 1000; + } + + isCloseToFeedbackDeadline(item: TaskGanttItem) { + if (!this.unit.allowFlexibleDates) { + return false; + } + + const task = item.task; + const diff = + this.normalizeDateUTC(task.localDeadlineDate().getTime() / 1000) - + this.normalizeDateUTC(item.end); + + return diff >= 0 && diff <= this.CLOSE_TO_FEEDBACK_DEADLINE_THRESHOLD * 24 * 60 * 60; + } + + toDateStr = (timestamp: number) => { + const d = new Date(timestamp * 1000); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; + }; + + saveTargetDates() { + for (const item of this.items) { + const td = item.taskDefinition; + if (!td) { + continue; + } + if (this.unsavedChanges(item)) { + this.saveTargetDate(item); + } + } + } + + saveTargetDate(item: TaskGanttItem) { + const td = item.taskDefinition; + const task = item.task; + + task.saveTargetDates(this.toDateStr(item.start), this.toDateStr(item.end)).subscribe({ + next: (data) => { + task.targetDueDate = data.targetDueDate; + task.targetStartDate = data.targetStartDate; + item.start = this.normalizeDateUTC(data.targetStartDate.getTime() / 1000); + item.end = this.normalizeDateUTC(data.targetDueDate.getTime() / 1000); + this.items = [...this.items]; + }, + error: (error) => { + this.alertService.error( + `Failed to save target date for ${td.abbreviation}: ${error}`, + 6000, + ); + }, + }); + } + + anyUnsavedChanges() { + return this.items.some((i) => this.unsavedChanges(i)); + } + + confirmSaveTargetDates() { + this.confirmationModalService.show( + 'Save Task Dates?', + `Do you want to save these new target dates for your tasks? You can always reset them to the unit's default later.`, + () => { + this.saveTargetDates(); + }, + ); + } + + confirmResetTargetDates() { + this.confirmationModalService.show( + 'Reset Task Dates?', + `Are you sure you want to reset all target dates to the unit's default? All modified dates will be reset.`, + () => { + this.project.resetTargetDates().subscribe({ + next: (_project) => { + for (const task of this.project.tasks) { + task.targetDueDate = null; + task.targetStartDate = null; + + const item = this.items.find((item) => item.id === task.definition.id.toString()); + if (item) { + item.start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + item.end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + } + } + this.items = [...this.items]; + }, + error: (error) => { + this.alertService.error(`Failed to reset target dates: ${error}`, 6000); + }, + }); + }, + ); + } + + // normalizeDateUTC = (ts: number) => { + // const d = new GanttDate(ts * 1000); + // // const utc = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 0, 0, 0, 0); + // return Math.floor(d.getUnixTime()); + // }; + + normalizeDateUTC = (ts: number) => { + const d = new GanttDate(ts * 1000); + // d.setHours(0, 0, 0, 0); + return Math.floor(d.startOfDay().getTime() / 1000); + }; + + // normalizeDateUTC = (ts: number) => { + // const d = new Date(ts * 1000); + // d.setHours(0, 0, 0, 0); + // return Math.floor(d.getTime() / 1000); + // }; + + toDateString(timestamp: number | Date) { + const date = timestamp instanceof Date ? timestamp : new Date(timestamp * 1000); + return date.toLocaleDateString('en-AU', { + month: 'short', + day: 'numeric', + // year: '2-digit', + }); + } + + unsavedChanges(item: TaskGanttItem) { + const task = item.task; + const start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + const end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + return start !== this.normalizeDateUTC(item.start) || end !== this.normalizeDateUTC(item.end); + } + + getTooltip(item: TaskGanttItem) { + return `${this.toDateString(item.start)} — ${this.toDateString(item.end)}`; + } + + public get earliestStartDate() { + const tasks = this.taskDefs() + .map((td) => this.project.findTaskForDefinition(td.id)) + .filter((t) => t?.startDate); + + if (!tasks.length) { + return Math.floor(this.unit.startDate.getTime() / 1000); + } + + const earliestTaskStart = Math.min(...tasks.map((t) => t.startDate.getTime() / 1000)); + + return Math.floor(Math.min(this.unit.startDate.getTime() / 1000, earliestTaskStart)); + } + + public get latestEndDate() { + const tasks = this.taskDefs() + .map((td) => this.project.findTaskForDefinition(td.id)) + .filter((t) => t?.localDueDate()); + + if (!tasks.length) { + return Math.floor(this.unit.endDate.getTime() / 1000); + } + + const latestTaskEnd = Math.max(...tasks.map((t) => t.localDueDate().getTime() / 1000)); + + return Math.floor(Math.max(this.unit.endDate.getTime() / 1000, latestTaskEnd)); + } + + ngOnInit(): void { + this.viewOptions = { + datePrecisionUnit: 'day', + start: new GanttDate(this.earliestStartDate), + end: new GanttDate(this.latestEndDate), + dragPreviewDateFormat: 'MMM dd', + }; + + this.unit.getTaskPrerequisites().subscribe({ + next: (prereqs) => { + this.allTaskPrerequisites = prereqs; + this.mapPrerequisites(); + for (const prerequisite of this.allTaskPrerequisites) { + prerequisite.taskDefinition.taskPrerequisitesCache.getOrCreate( + prerequisite.id, + this.taskPrerequisiteService, + prerequisite, + ); + } + + for (const td of this.unit.taskDefinitions) { + const prerequisites = td.taskPrerequisitesCache.currentValues; + const definitions = this.unit.taskDefinitions; + for (const prerequisite of prerequisites) { + prerequisite.taskDefinition = definitions.find( + (td) => td.id === prerequisite.taskDefinitionId, + ); + prerequisite.prerequisite = definitions.find( + (td) => td.id === prerequisite.prerequisiteId, + ); + } + } + + this.refreshItems(); + }, + error: (error) => { + this.alertService.error(`Failed to get task prerequisites: ${error}`, 6000); + }, + }); + } + + refreshItems(scroll: boolean = true) { + this.taskPrerequisites = this.allTaskPrerequisites.filter((pre) => + this.taskDefs().find((td) => td.id === pre.taskDefinitionId), + ); + + const taskDefinitions = this.taskDefs(); + this.items = []; + this.baselineItems = []; + + const _items: TaskGanttItem[] = []; + const _baselineItems: GanttBaselineItem[] = []; + + for (const td of taskDefinitions) { + const task = this.project.findTaskForDefinition(td.id); + + const item: TaskGanttItem = { + id: td.id.toString(), + title: `${td.abbreviation} ${td.name}`, + start: this.normalizeDateUTC(task.startDate.getTime() / 1000), + end: this.normalizeDateUTC(task.localDueDate().getTime() / 1000), + expandable: false, + draggable: this.project.unit.allowFlexibleDates, + // color: this.gradeService.gradeColors[td.targetGrade], + expanded: false, + color: '#3333ff', + taskDefinition: td, + task: task, + // progress: 0.5, + originalLinks: [], + links: this.taskPrerequisites + .filter((p) => p.prerequisiteId === td.id) + // .filter((p) => p.taskDefinitionId === td.id) + .map((p) => { + let color: string; + + switch (p.taskStatus) { + case 'ready_for_feedback': + color = 'rgba(0, 121, 216, 0.1)'; + break; + case 'complete': + color = 'rgba(91, 183, 91, 0.1)'; + break; + case 'discuss': + color = 'rgba(49, 176, 213, 0.1)'; + break; + case 'demonstrate': + color = 'rgba(49, 176, 213, 0.1)'; + break; + default: + color = 'gray'; + } + const link: GanttLink = { + type: GanttLinkType.fs, + link: p.taskDefinitionId.toString(), + // link: p.prerequisiteId.toString(), + color: { + default: color, + active: color, + }, + }; + + return link; + }), + }; + + // if ( + // item.links.length && + // (this.isCloseToFeedbackDeadline(item) || this.isPastFeedbackDeadline(item)) + // ) { + // const task = this.project.findTaskForDefinition(td.id); + + // item.start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + // item.end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + + // // If the task defaults are still invalid, reset them to the task definition default + // if (this.isCloseToFeedbackDeadline(item) || this.isPastFeedbackDeadline(item)) { + // item.start = this.normalizeDateUTC(td.startDate.getTime() / 1000); + // item.end = this.normalizeDateUTC(td.localDueDate().getTime() / 1000); + // } + // } + + const originalItem = {...item}; + item.originalLinks = [...(originalItem.links as GanttLink[])]; + + this.items.push(item); + _items.push(item); + + // Create baseline item + const baselineItem = {...item}; + + const tdTargetDate = + (this.targetGrade === 1 + ? td.cTargetDate + : this.targetGrade === 2 + ? td.dTargetDate + : this.targetGrade === 3 + ? td.hdTargetDate + : td.targetDate) ?? td.targetDate; + + const tdStartDate = + (this.targetGrade === 1 + ? td.cStartDate + : this.targetGrade === 2 + ? td.dStartDate + : this.targetGrade === 3 + ? td.hdStartDate + : td.startDate) ?? td.startDate; + + baselineItem.start = this.normalizeDateUTC(tdStartDate.getTime() / 1000); + baselineItem.end = this.normalizeDateUTC(tdTargetDate.getTime() / 1000); + + _baselineItems.push(baselineItem); + + // if (this.unsavedChanges(item)) { + // this.saveTargetDate(item); + // } + } + + this.items = [..._items]; + setTimeout(() => { + this.baselineItems = [..._baselineItems]; + }); + + if (scroll) { + this.ganttComponent.scrollToToday(); + } + + if (this.router.globals.params.taskDef && scroll) { + const taskItem = this.items.find((item) => item.id === this.router.globals.params.taskDef); + if (taskItem) { + this.ganttComponent.scrollToDate(taskItem.start); + taskItem.highlighted = true; + this.animateBackground = true; + + setTimeout(() => { + const el = document.querySelector(`[data-gantt-id="${taskItem.id}"]`) as HTMLElement; + + el?.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'nearest', + }); + }); + setTimeout(() => (taskItem.highlighted = false), 1000); + setTimeout(() => (this.animateBackground = false), 2000); + } + this.router.stateService.go( + this.router.globals.current.name, + {taskDef: null}, + {location: 'replace', notify: false, reload: false}, + ); + } + } + + public taskDefs(): TaskDefinition[] { + if (!this.project || !this.project.unit.taskDefinitions) { + return []; + } + + return this.project.unit.taskDefinitions + .filter((taskDef) => taskDef.targetGrade <= this.targetGrade) + .sort((a, b) => { + const taskA = this.project.findTaskForDefinition(a.id); + const taskB = this.project.findTaskForDefinition(b.id); + + const dateA = taskA?.startDate ?? a.startDate; + const dateB = taskB?.startDate ?? b.startDate; + + return new Date(dateA).getTime() - new Date(dateB).getTime(); + }); + } +} diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index 8ce9be0be3..661acd16e7 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -1,6 +1,5 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ 'doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step' - 'doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step' 'doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee deleted file mode 100644 index d29d0f65da..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee +++ /dev/null @@ -1,19 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step', []) - -# -# Allows students to select the target grade they are hoping -# to achieve with their portfolio -# -.directive('portfolioGradeSelectStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html' - controller: ($scope, newProjectService, gradeService) -> - $scope.grades = gradeService.grades - $scope.agreedToAssessmentCriteria = $scope.projectHasLearningSummaryReport() - $scope.chooseGrade = (idx) -> - $scope.project.submittedGrade = idx - newProjectService.update($scope.project).subscribe((project) -> - $scope.project.refreshBurndownChartData() - ) -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html new file mode 100644 index 0000000000..575a9f5faf --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -0,0 +1,100 @@ +
+ + + + +

Select Grade

+
+
+ + +

+ In preparing your portfolio, you need to undertake a self-assessment. Use the unit's + assessment criteria to determine the grade your portfolio should be awarded. +

+ + + + + + warning + Read the assessment criteria + + + + +

+ Make sure that you have reviewed the Assessment Criteria for the grade you are applying + for. Each grade will have a list of criteria that you can use to determine if you meet + the requirements to achieve that grade. +

+
+ + + + I have read the Assessment Criteria for this unit + + +
+ + + + @if (agreedToAssessmentCriteria) { + + + + Grade Application + + + + +

+ Select the grade you are applying for {{ unit.code }} + {{ unit.name }} below. +

+
+ + + + @for (grade of gradeValues; track grade) { + + + + } + + +

+ Make sure your Learning Summary Report justifies how your portfolio + demonstrates you have + met all unit learning outcomes to a {{ targetGrade }} level +

+
+
+ } +
+ + + + + + +
+
diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts new file mode 100644 index 0000000000..ea3330fd40 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts @@ -0,0 +1,60 @@ +import {Component, Injector, Input} from '@angular/core'; +import {Project, Unit} from 'src/app/api/models/doubtfire-model'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolio-grade-select-step', + templateUrl: 'portfolio-grade-select-step.component.html', + styleUrls: ['portfolio-grade-select-step.component.scss'], +}) +export class PortfolioGradeSelectStepComponent { + @Input() project: Project; + @Input() unit: Unit; + + public agreedToAssessmentCriteria: boolean = false; + + constructor( + private gradeService: GradeService, + private injector: Injector, + private projectService: ProjectService, + private alertService: AlertService, + ) { + this.$scope = this.injector.get('$scope'); + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + updateSubmittedGrade(newGrade: number): void { + const previousSubmittedGrade = this.project.submittedGrade; + this.project.submittedGrade = newGrade; + + this.projectService.update(this.project).subscribe( + (project) => { + project.refreshBurndownChartData?.(); + }, + (error) => { + this.project.submittedGrade = previousSubmittedGrade; + console.error('Error updating target grade:', error); + this.alertService.error(`Could not update grade: ${error}`, 6000); + }, + ); + } + + // TODO: remove this once parent component has been migrated + private $scope: any; + goToNextStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(1); + } + } + + goToPreviousStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(-1); + } + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss deleted file mode 100644 index bfc229c4b1..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss +++ /dev/null @@ -1,10 +0,0 @@ -.project-portfolio-wizard .portfolio-grade-select-step { - .confirm-read-assessment-criteria { - font-size: 1.2em; - } - .select-the-grade { - .btn { - padding: 1em; - } - } -} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html deleted file mode 100644 index 244c110857..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html +++ /dev/null @@ -1,60 +0,0 @@ -
-
-

Select Grade

-
-
-

- In preparing your portfolio, you need to undertake a self assessment. Use the unit's assessment criteria to - determine the grade your portfolio should be awarded. -

-
-
-

Read the assessment criteria

- Make sure that you have reviewed the Assessment Criteria for the grade you are applying for. Each grade will - have a list of criteria that you can use to determine if you meet the requirements to achieve that grade. -
-
- - -
-
- -
-
-

Grade Application

- Select the grade you are applying for {{unit.name}} below. -
-
-
- -
-

- Make sure your Learning Summary Report justifies how your portfolio demonstrates you have - met all unit learning outcomes to a {{targetGrade}} level -

-
-
- -
- - -
diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html new file mode 100644 index 0000000000..7444d7176c --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html @@ -0,0 +1,26 @@ +@if (loading) { +
+
Loading tasks...
+ +
+} @else { + @if (tasksInPortfolio.length === 0) { +
+ assignment_late +

No tasks found

+
+ } @else { +
    + @for (task of tasksInPortfolio; track task) { +
  1. +
    +
    +
    {{ task.definition.abbreviation }} — {{ task.definition.name }}
    +
    + +
    +
  2. + } +
+ } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.scss b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts new file mode 100644 index 0000000000..e425d93976 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts @@ -0,0 +1,36 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; +import {Task} from 'src/app/api/models/task'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-portfolio-included-tasks', + templateUrl: 'portfolio-included-tasks.component.html', + styleUrls: ['portfolio-included-tasks.component.scss'], +}) +export class PortfolioIncludedTasksComponent implements OnInit { + @Input() project: Project; + + constructor(private alertService: AlertService) {} + + loading: boolean = false; + + tasksInPortfolio: Task[] = []; + ngOnInit() { + this.loading = true; + this.project.getTasksIncludedInPortfolio().subscribe({ + next: (tasks) => { + for (const taskId of tasks) { + const task = this.project.tasks.find((t) => t.id === taskId); + if (task) { + this.tasksInPortfolio.push(task); + } + } + this.loading = false; + }, + error: (error) => { + this.alertService.error(`Failed to get tasks for portfolio: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html index ba23ed6f53..4a9a098324 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html @@ -51,19 +51,15 @@

Portfolio Processing

  • {{file.name}}
  • -
    -

    - You have included {{selectedTasks().length}} tasks in your portfolio. If you wish to add or - remove some of these tasks, please review the Select Tasks step to adjust your alignments of each - task to the unit's learning outcomes. Each task will be attached in the order below: -

    -
      -
    1. - - {{task.definition.name}} -
    2. -
    -
    +

    + Only submitted tasks will be included in your portfolio. If a task is missing from the list, + ensure that you have submitted it before compiling your portfolio. All feedback and comments + for each task will appear in the final portfolio, so you can add any additional comments now + if there's something you'd like to address. +

    The following tasks will be included + automatically in this order:

    +

    +
    @@ -91,7 +87,14 @@

    Create Your Portfolio

    Download Portfolio

    -
    This is the exact same document your assessor will see
    +
    +

    + This is the exact same document your assessor will see. +

    +

    + You're done! There's nothing left for you to do. Your portfolio has been submitted. +

    +

    Preparing your portfolio involves 5 steps:

    -
      +
      1. Select your Grade you are applying for
      2. Upload your Learning Summary Report
      3. -
      4. Select the Tasks you want included
      5. Upload any Other Resources you want to add
      6. Compile your resources into your portfolio and review
      diff --git a/src/app/projects/states/portfolio/portfolio.coffee b/src/app/projects/states/portfolio/portfolio.coffee index 4257ab1757..0224ae100d 100644 --- a/src/app/projects/states/portfolio/portfolio.coffee +++ b/src/app/projects/states/portfolio/portfolio.coffee @@ -32,15 +32,12 @@ angular.module('doubtfire.projects.states.portfolio', [ summaryStep: title: "Learning Summary Report" seq: 3 - taskStep: - title: "Select Tasks" - seq: 4 otherFilesStep: title: "Upload Other Files" - seq: 5 + seq: 4 reviewStep: title: "Review Portfolio" - seq: 6 + seq: 5 $scope.setActiveTab = (tab) -> $scope.activeTab = tab $scope.activeTab.active = true @@ -82,29 +79,22 @@ angular.module('doubtfire.projects.states.portfolio', [ # when f.idx is 0 it's the LSR f.idx isnt 0 - # Gets whether the unit has ilos - $scope.unitHasILOs = $scope.unit.ilos.length > 0 - # Gets selected tasks in the task selector $scope.selectedTasks = -> - if $scope.unitHasILOs - # Filter by aligned tasks that are included - tasks = _.filter $scope.project.tasks, (t) -> - hasAlignmentsForTask = _.find($scope.project.taskOutcomeAlignments, (ta) -> ta.task.id == t.id )? - t.includeInPortfolio and hasAlignmentsForTask - else - # Filter by included in portfolio - tasks = _.filter $scope.project.tasks, (t) -> t.includeInPortfolio + # Filter by included in portfolio + tasks = $scope.project.tasks tasks = _.filter tasks, (t) -> !_.includes(newTaskService.toBeWorkedOn, t.status) _.sortBy tasks, (t) -> t.definition.seq # Jump to a step if $scope.project.portfolioAvailable or $scope.project.compilePortfolio $scope.setActiveTab $scope.tabs.reviewStep + else if not $scope.project.submittedGrade? + $scope.setActiveTab $scope.tabs.welcomeStep else if $scope.projectHasDraftLearningSummaryReport $scope.setActiveTab $scope.tabs.summaryStep else if $scope.projectHasLearningSummaryReport() - $scope.setActiveTab $scope.tabs.taskStep + $scope.setActiveTab $scope.tabs.otherFilesStep else $scope.setActiveTab $scope.tabs.welcomeStep diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index 1c009b47ab..934f90e76f 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -7,9 +7,12 @@ - + + -
    diff --git a/src/app/projects/states/staff-notes/staff-notes.component.html b/src/app/projects/states/staff-notes/staff-notes.component.html new file mode 100644 index 0000000000..9c89b3a391 --- /dev/null +++ b/src/app/projects/states/staff-notes/staff-notes.component.html @@ -0,0 +1,127 @@ +
    + @if (!loadingStaffNotes && project?.staffNoteCount === 0) { +
    + No staff notes for {{ project.student.preferredName }} {{ project.student.lastName }} +
    + } +
    + @if (!loadingStaffNotes) { + @for (note of project?.staffNoteCache?.currentValues; track note) { + @if (note.replyToId) { +
    +
    + reply +
    + @if (note.replyTo) { + + Replying to {{ note.replyTo.user.preferredName }} + {{ note.replyTo.user.lastName }} ({{ note.replyTo.user.nickname }}) + + {{ note.replyTo.note }} + } @else { + Replying to: Deleted note + } +
    +
    +
    + } + +
    + @if (note.authorIsMe) { + edit + } + reply + delete +
    +
    + + + {{ note.user?.firstName }} {{ note.user?.lastName }} +
    + {{ note.createdAt | humanizedDate }} +
    +
    + + + @if (editingNote && editingNote.id === note.id) { + + Update Note + +
    + + +
    +
    + } @else { +
    + } +
    +
    + } + } @else { + + } +
    + +
    + @if (replyingToNote) { +
    +
    + reply +
    + + Replying to {{ replyingToNote.user.firstName }} {{ replyingToNote.user.lastName }} ({{ + replyingToNote.user.nickname + }}) + + {{ replyingToNote.note }} +
    +
    + close +
    + } + + + Staff Note + +
    + +
    +
    +
    +
    diff --git a/src/app/projects/states/staff-notes/staff-notes.component.scss b/src/app/projects/states/staff-notes/staff-notes.component.scss new file mode 100644 index 0000000000..a6d41ed2d2 --- /dev/null +++ b/src/app/projects/states/staff-notes/staff-notes.component.scss @@ -0,0 +1,27 @@ +.mat-icon { + color: #9696969d; + font-size: 20px; + width: 20px; + height: 20px; + cursor: pointer; + vertical-align: middle; + text-align: center; + margin-left: 0.3em; +} + +.mat-icon:hover { + color: black; +} + +@keyframes blueGlowFade { + 0% { + background-color: rgba(66, 133, 244, 0.6); + } + 100% { + background-color: transparent; + } +} + +.flash-highlight { + animation: blueGlowFade 1s ease-out; +} diff --git a/src/app/projects/states/staff-notes/staff-notes.component.spec.ts b/src/app/projects/states/staff-notes/staff-notes.component.spec.ts new file mode 100644 index 0000000000..fcd374cbfe --- /dev/null +++ b/src/app/projects/states/staff-notes/staff-notes.component.spec.ts @@ -0,0 +1,22 @@ +import {ComponentFixture, TestBed} from '@angular/core/testing'; + +import {StaffNotesComponent} from './staff-notes.component'; + +describe('StaffNotesComponent', () => { + let component: StaffNotesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [StaffNotesComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(StaffNotesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/projects/states/staff-notes/staff-notes.component.ts b/src/app/projects/states/staff-notes/staff-notes.component.ts new file mode 100644 index 0000000000..78821277a5 --- /dev/null +++ b/src/app/projects/states/staff-notes/staff-notes.component.ts @@ -0,0 +1,147 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import {Project, UserService} from 'src/app/api/models/doubtfire-model'; +import {StaffNote} from 'src/app/api/models/staff-note'; +import {StaffNoteService} from 'src/app/api/services/staff-note.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-staff-notes', + templateUrl: './staff-notes.component.html', + styleUrl: './staff-notes.component.scss', +}) +export class StaffNotesComponent implements OnInit { + @ViewChild('staffNotesContainer') staffNotesContainer!: ElementRef; + @ViewChild('staffNoteEditor', {static: false}) staffNoteEditor!: ElementRef; + + @Input() project: Project; + + loadingStaffNotes: boolean = true; + + noteText: string = ''; + + editingNote?: StaffNote; + editingNoteText?: string = ''; + + replyingToNote?: StaffNote; + + hoveredNoteId: number | null = null; + + constructor( + private userService: UserService, + private staffNoteService: StaffNoteService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + ) {} + ngOnInit(): void { + this.loadingStaffNotes = true; + this.staffNoteService.loadStaffNotes(this.project).subscribe((notes) => { + this.loadingStaffNotes = false; + this.staffNoteService.updateStaffNoteReplies(this.project?.staffNoteCache.currentValues); + this.scrollDown(); + }); + } + + scrollToComment(commentID: number) { + document.querySelector(`#comment-${commentID}`).scrollIntoView(); + } + + scrollDown() { + setTimeout(() => { + const el = this.staffNotesContainer.nativeElement; + el.scrollTop = el.scrollHeight; + }, 50); + } + + public submitNote() { + const noteText = this.noteText.trim(); + if (noteText === '') { + return; + } + + this.noteText = ''; + + this.staffNoteService.addNote(this.project, noteText, this.replyingToNote).subscribe({ + next: (note) => { + this.alertService.success('Succesfully submitted note', 4000); + this.scrollDown(); + this.project.staffNoteCount++; + this.replyingToNote = null; + this.staffNoteService.updateStaffNoteReplies(this.project?.staffNoteCache.currentValues); + }, + error: (error) => { + this.alertService.error(`Failed to create note: ${error}`, 4000); + this.noteText = noteText; + }, + }); + } + + public updateNote() { + const noteText = this.editingNoteText.trim(); + if (noteText === '' || !this.editingNote) { + return; + } + + this.staffNoteService.updateNote(this.project, this.editingNote, noteText).subscribe({ + next: (note) => { + this.alertService.success('Succesfully updated note', 4000); + this.editingNote = null; + this.editingNoteText = ''; + }, + error: (error) => { + this.alertService.error(`Failed to update note: ${error}`, 4000); + }, + }); + } + + public deleteNote(note: StaffNote) { + this.confirmationModalService.show( + 'Delete note', + 'Are you sure want to delete this staff note?', + () => { + note.delete(); + }, + ); + } + + public replyToNote(note: StaffNote) { + this.replyingToNote = note; + } + public cancelReplyingToNote() { + this.replyingToNote = null; + } + + public editNote(note: StaffNote) { + if (!note.authorIsMe) { + return; + } + + this.editingNote = note; + this.editingNoteText = note.note; + setTimeout(() => { + this.autoResizeStaffNoteEditor(); + this.staffNoteEditor?.nativeElement.focus(); + }); + } + + public cancelEditingNote() { + this.editingNote = null; + this.editingNoteText = ''; + } + + public autoResizeStaffNoteEditor() { + const el = this.staffNoteEditor.nativeElement; + el.style.height = 'auto'; + el.offsetHeight; + el.style.height = el.scrollHeight + 'px'; + } + + scrollToNote(note: StaffNote): void { + const el = document.getElementById(`note-${note.id}`); + if (el) { + el.scrollIntoView({behavior: 'smooth', block: 'center'}); + el.classList.add('flash-highlight'); + setTimeout(() => el.classList.remove('flash-highlight'), 1000); + } + } +} diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html new file mode 100644 index 0000000000..97c5d30809 --- /dev/null +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -0,0 +1,246 @@ +
    + @if (loadingStudentData) { + + } +
    +
    +
    +
    + Scan a student's QR code to instantly load their project and mark submissions. +
    + +
    + + +
    + @if (attendance && unit) { +
    + + + @for (td of unit?.taskDefinitionCache.values | async; track td) { + {{ td.abbreviation }} - {{ td.name }} + } + + + @if (selectedTaskDefinition) { + + } +
    + } + +
    +
    + @if (project && project?.student) { +
    +
    +
    + {{ project?.student?.firstName }} {{ project?.student?.lastName }} + @if (project?.student.studentId) { + ({{ project?.student.studentId }}) + } +
    +
    + Target Grade: {{ getTargetTradeString(project?.targetGrade) }} +
    +
    + } @else { +
    +
    Click the QR code to open the scanner..
    + } + +
    + + @if (project && !filteredTasks.length) { +
    No tasks to discuss.
    + } + + @for (task of filteredTasks; track task) { + + @if (task) { +
    +
    + + +
    +

    {{ task.definition.name }}

    + + {{ task.definition.abbreviation }} - + {{ getTargetTradeString(task.definition.targetGrade) }} Task + +
    + @if (task.hasGrade()) { +
    + {{ task.gradeDesc() }} + +
    + } + + + +
    + +
    + } +
    + } + + +
    + @if (project) { +
    + @if (this.allTasks?.length > 0) { + @if (this.filteredTasks?.length < this.allTasks?.length) { + + } @else { + + } + } +
    + } + + +
    + + @if (project && filteredTasks.length) { +
    +
    + @if (attendance) { + + } @else { + + + + + } +
    +
    + } + + @if (selectedTask && project) { + + + + + + + + @if (footerTabView === TutorDiscussionTabView.SHOW_COMMENTS) { +
    + + + + +
    + } @else if (footerTabView === TutorDiscussionTabView.SHOW_STAFF_NOTES) { + + } @else if (footerTabView === TutorDiscussionTabView.SHOW_DISCUSSION_PROMPTS) { + + } + } +
    diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.scss b/src/app/projects/states/tutor-discussion/tutor-discussion.component.scss new file mode 100644 index 0000000000..37fe08fe84 --- /dev/null +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.scss @@ -0,0 +1,114 @@ +@use 'sass:map'; +@use '@angular/material' as mat; + +// $my-palette: mat.define-palette(mat.$indigo-palette); +@import '../../../../theme.scss'; +@import '../../../../styles/mixins/task-list.scss'; +@import '../../../../styles/mixins/scrollable.scss'; + +$my-palette: mat.define-palette($md-formatif); + +:host { + --background-gray: rgba(0, 0, 0, 0.04); + padding-right: 8px; + border-right-color: rgba(0, 0, 0, 0.1); + border-right-style: solid; + border-right-width: 1px; +} + +:host ::ng-deep div.mat-expansion-panel-body { + padding-right: 0 !important; +} + +user-icon { + margin-right: 10px; +} + +.mat-mdc-list-item { + border: none; +} + +.mat-mdc-list-item .notification { + height: 8px; + width: 8px; + margin-right: 8px; + + border-radius: 50%; + display: inline-block; + + background-color: transparent; + + &.active { + background-color: mat.get-color-from-palette($my-palette, 500); + } + + &.active.similarities { + background-color: #f44336; + } +} + +.mat-mdc-list-item .item-content { + height: 60px; + border-radius: 20px; +} + +.mat-mdc-list-item .item-content:hover { + cursor: pointer; +} + +// .tasks-viewport.list-group-item-text-extended { +// margin-top: 0.5em; +// line-height: 1.3; + +// p { +// margin-bottom: 0; +// padding: 0; +// color: gray; +// } +// } + +.mdc-list-item__start.mat-mdc-list-option-checkbox-before { + margin-right: 0 !important; + padding: 0 !important; +} + +.medium-icon-button { + width: 75px !important; + height: 75px !important; +} + +// Hide auto-injected QR scanner elements that are not needed in the UI +// We only hide this if we found a "back camera" on user's device +.qr-reader-hide-bloat #qr-reader__header_message, +.qr-reader-hide-bloat #qr-reader__dashboard_section, +.qr-reader-hide-bloat #qr-reader__dashboard_section_csr, +.qr-reader-hide-bloat #qr-reader > div:not([id]):not([class]), +.qr-reader-hide-bloat #qr-reader__scan_region > div:not([id]):not([class]), +.qr-reader-hide-bloat #html5-qrcode-button-camera-stop, +.qr-reader-hide-bloat #html5-qrcode-button-camera-start { + display: none !important; +} + +#qr-reader img, +#html5-qrcode-anchor-scan-type-change { + display: none !important; +} + +#html5-qrcode-button-camera-stop, +#html5-qrcode-button-camera-start { + @apply bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded shadow w-full uppercase; + max-width: 1000px; + height: 45px; + margin-top: 15px; +} + +#html5-qrcode-button-camera-permission { + @apply bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded shadow w-full uppercase; + width: 100%; + max-width: 250px; + height: 60px; +} + +.comment-user-icon-wrapper.ng-star-inserted { + width: auto !important; +} diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts new file mode 100644 index 0000000000..25f6e0711e --- /dev/null +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts @@ -0,0 +1,22 @@ +import {ComponentFixture, TestBed} from '@angular/core/testing'; + +import {TutorDiscussionComponent} from './tutor-discussion.component'; + +describe('TutorDiscussionComponent', () => { + let component: TutorDiscussionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TutorDiscussionComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(TutorDiscussionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts new file mode 100644 index 0000000000..43416b60c1 --- /dev/null +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -0,0 +1,454 @@ +import {AfterViewInit, Component, Input, ViewChild, ViewEncapsulation} from '@angular/core'; +import {MatSelectionList} from '@angular/material/list'; +import {MatTabChangeEvent} from '@angular/material/tabs'; +import {StateService, UIRouter} from '@uirouter/core'; +import {Html5QrcodeScanner, Html5QrcodeScannerState} from 'html5-qrcode'; +import { + AuthenticationService, + Project, + ProjectService, + Task, + TaskCommentService, + TaskDefinition, + TaskService, + TaskStatusEnum, + TutorialStream, + Unit, + UnitService, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +enum TutorDiscussionTabView { + SHOW_COMMENTS, + SHOW_STAFF_NOTES, + SHOW_DISCUSSION_PROMPTS, +} +@Component({ + selector: 'f-tutor-discussion', + templateUrl: './tutor-discussion.component.html', + styleUrl: './tutor-discussion.component.scss', + encapsulation: ViewEncapsulation.None, // enables custom material-ui css +}) +export class TutorDiscussionComponent implements AfterViewInit { + @Input() unitId: number; + @Input() username: string; + @Input() attendance: boolean; + + @ViewChild('tasks') tasksList: MatSelectionList; + selectedTaskDefinition: TaskDefinition | null = null; + + public filteredTasks: Task[] = []; + public allTasks: Task[] = []; + + public unit: Unit | null; + public project: Project | null; + + public selectedTask: Task | null; + + public scanningQr: boolean = false; + public loadingStudentData: boolean = false; + + private html5QrcodeScanner: Html5QrcodeScanner; + + private _unitId: number; + private _username: string; + + public TutorDiscussionTabView = TutorDiscussionTabView; + public footerTabView: TutorDiscussionTabView = TutorDiscussionTabView.SHOW_COMMENTS; + + constructor( + private unitService: UnitService, + private authService: AuthenticationService, + private userService: UserService, + private projectService: ProjectService, + private gradeService: GradeService, + private state: StateService, + private alertService: AlertService, + private route: UIRouter, + private taskCommentService: TaskCommentService, + private taskService: TaskService, + ) {} + + public currentUserTutorsInStream(tutorialStream: TutorialStream): boolean { + const user = this.userService.currentUser; + const tutorials = this.unit.tutorials.filter( + (t) => + t.tutorialStream.abbreviation === tutorialStream.abbreviation && + t.tutorialStream.name === tutorialStream.name, + ); + if (tutorials.some((t) => t.tutor.id === user.id)) { + return true; + } + return false; + } + + onTabChange(event: MatTabChangeEvent): void { + if (event.index === 0) { + this.showComments(); + } else if (event.index === 1) { + this.showStaffNotes(); + } else if (event.index === 2) { + this.showDiscussionPrompts(); + } + } + + public showComments() { + this.footerTabView = TutorDiscussionTabView.SHOW_COMMENTS; + } + + public showStaffNotes() { + this.footerTabView = TutorDiscussionTabView.SHOW_STAFF_NOTES; + } + + public showDiscussionPrompts() { + this.footerTabView = TutorDiscussionTabView.SHOW_DISCUSSION_PROMPTS; + } + + public ngAfterViewInit(): void { + this.authService.afterAuthCall((result) => { + if (!result) { + return this.state.go('sign_in'); + } else { + if (this.userService.currentUser.systemRole === 'Student') { + // Avoid prompting students for camera permissions before redirecting to unauthorised state + return; + } + if (this.unitId) { + this._unitId = Number(this.unitId); + if (!this.attendance) { + // Tutor discussion view + if (this.username) { + this._username = this.username; + this.getStudentTasks(); + } else { + this.scanQrCode(); + } + } else { + this.getUnit().then((u) => { + this.unit = u; + }); + } + } + } + }); + } + + private decodeQrCode(data: string) { + if (!this.scanningQr || this.loadingStudentData) { + return; + } + + try { + const params = new URL(data).searchParams; + const unitId = parseInt(params.get('unitId')); + const projectId = parseInt(params.get('projectId')); + const username = params.get('username'); + + if ((!isNaN(unitId) && !isNaN(projectId)) || username) { + if (unitId) { + this._unitId = unitId; + } + if (username) { + this._username = username; + } + + this.changeProject(); + } + } catch { + // QR code data is invalid + } + } + + public closeQrReader(): void { + if (!this.project) { + // Exiting the route entirely + if (this.unitId) { + this.route.stateService.go('units/tasks/inbox', { + unitId: this.unitId, + }); + } else { + this.route.stateService.go('home'); + } + } else { + // Close the camera view + this.scanningQr = false; + } + } + + private changeProject() { + this.html5QrcodeScanner.pause(true); + this.loadingStudentData = true; + setTimeout(() => { + try { + this.getStudentTasks(); + } catch (_e) { + this.alertService.error(`Invalid QR code`, 2000); + this.loadingStudentData = false; + + setTimeout(() => { + this.html5QrcodeScanner.resume(); + }, 2000); + } + }); + } + + hideQrScannerBloat: boolean = true; + + public scanQrCode() { + if (this.attendance && !this.selectedTaskDefinition) { + this.alertService.error('You must select a task first', 3000); + return; + } + + this.scanningQr = true; + this.loadingStudentData = false; + + if ( + this.html5QrcodeScanner && + this.html5QrcodeScanner.getState() === Html5QrcodeScannerState.PAUSED + ) { + this.html5QrcodeScanner.resume(); + } else { + this.html5QrcodeScanner?.clear(); + + // Trigger video permissions + // If we call getUserMedia when html5QrcodeScanner is already active, the scanner will break on iOS + navigator.mediaDevices + .getUserMedia({video: true}) + .then(() => { + return navigator.mediaDevices.enumerateDevices(); + }) + .then((devices) => { + // Find the deviceId of the back camera + const backCameras = devices.filter( + (d) => d.kind === 'videoinput' && d.label.toLowerCase().includes('back camera'), + ); + + const html5QrcodeData = { + hasPermission: true, + lastUsedCameraId: backCameras[0]?.deviceId ?? null, + }; + localStorage.setItem('HTML5_QRCODE_DATA', JSON.stringify(html5QrcodeData)); + + // Hide most of the UI if we found and set the back camera + // Otherwise, we need to reveal the UI so that the user can select which camera to use + this.hideQrScannerBloat = html5QrcodeData.lastUsedCameraId ? true : false; + + setTimeout(() => { + // Only init the scanner once and let it run in the background + this.html5QrcodeScanner = new Html5QrcodeScanner( + 'qr-reader', // id of the div in the html + {fps: 10, qrbox: 250}, + false, + ); + + this.html5QrcodeScanner.render( + (data) => { + this.decodeQrCode(data); + }, + (_error) => { + // console.error(_error); + }, + ); + }); + }); + } + } + + public loadTaskComments(event: MouseEvent, task: Task) { + event.stopPropagation(); + this.selectedTask = task; + } + + public setSelectedTasksStatus(status: TaskStatusEnum) { + const selectedTasks = this.tasksList.selectedOptions.selected.map((taskOption) => { + return taskOption.value as Task; + }); + + if (status === 'complete') { + const blockedTasks = selectedTasks.filter( + (task) => !task.definition.assessInPortfolioOnly && !task.canMarkComplete, + ); + if (blockedTasks.length > 0) { + this.alertService.error( + 'Some selected tasks cannot be marked as complete until they are marked as discussed in class.', + 5000, + ); + } + } + + for (const task of selectedTasks) { + if ( + status === 'complete' && + !task.definition.assessInPortfolioOnly && + !task.canMarkComplete + ) { + continue; + } + + if (task.definition.assessInPortfolioOnly) { + task.updateTaskStatus(status === 'complete' ? 'working_on_it' : status, true); + } else { + task.updateTaskStatus(status, true); + } + } + } + + public get canMarkSelectedTasksComplete(): boolean { + const selectedTasks = this.tasksList?.selectedOptions?.selected ?? []; + if (!selectedTasks.length) { + return false; + } + + return selectedTasks.every((taskOption) => { + const task = taskOption.value as Task; + return task.definition.assessInPortfolioOnly || task.canMarkComplete; + }); + } + + public markSelectedTasksDicussed() { + const selectedTasks = this.tasksList.selectedOptions.selected; + for (const taskOption of selectedTasks) { + const task = taskOption.value as Task; + task.markAsDiscussed(); + } + } + + public markSelectedTasksCheckedIn() { + const selectedTasks = this.tasksList.selectedOptions.selected; + if (selectedTasks.length > 1) { + this.alertService.error('Can only check-in 1 task at a time', 5000); + return; + } + for (const taskOption of selectedTasks) { + const task = taskOption.value as Task; + this.taskService.checkInTaskForStudent(task).subscribe({ + next: () => { + this.taskService.notifyStatusChange(task); + this.alertService.success('Successfully checked in', 2500); + }, + error: (_error) => { + this.alertService.error('Failed to check-in', 5000); + }, + }); + } + } + + private getUnit(): Promise { + return new Promise((resolve, reject) => { + this.unitService.get({id: this._unitId}).subscribe({ + next: (unit) => { + setTimeout(() => { + resolve(unit); + }); + }, + error: (err) => { + reject(err); + }, + }); + }); + } + + private loadStudents(unit: Unit): Promise { + return new Promise((resolve, reject) => { + this.projectService.loadStudents(unit, false, false).subscribe((projects) => { + const project = projects.find((p) => p.student.username === this._username); + if (!project) { + reject('Student is not a part of this unit'); + } + resolve(project); + }); + }); + } + + private getProject(unit: Unit, projectId: number): Promise { + return new Promise((resolve, reject) => { + this.projectService.loadProject(projectId, unit, true).subscribe((project) => { + if (!project) { + reject('No project found'); + } + resolve(project); + }); + }); + } + + public getTargetTradeString(grade: number) { + return this.gradeService.grades[grade]; + } + + public refresh() { + this.decodeQrCode('{"unitId":2,"projectId":20}'); + } + + statusesToInclude: TaskStatusEnum[] = [ + 'demonstrate', + 'ready_for_feedback', + 'discuss', + 'attention_required', + 'need_help', + // 'complete', + 'fix_and_resubmit', + 'redo', + ]; + + public viewAllSubmittedTasks() { + this.filteredTasks = [...this.allTasks]; + } + + public viewAllFilteredTasks() { + const discussionTasks = this.project?.tasks.filter((task) => + this.statusesToInclude.includes(task.status), + ); + this.filteredTasks = [...discussionTasks]; + } + + public getStudentTasks(): void { + console.time('getStudentTasks()'); + // this.project = null; + // this.filteredTasks = []; + // this.selectedTask = null; + + this.getUnit() + .then((_unit) => { + this.unit = _unit; + return this.loadStudents(this.unit); + }) + .then((student) => { + return this.getProject(this.unit, student.id); + }) + .then((project) => { + const discussionTasks = project.tasks.filter((task) => + this.statusesToInclude.includes(task.status), + ); + if (!this.attendance) { + this.filteredTasks = [...discussionTasks]; + this.allTasks = [ + ...project.tasks.filter( + (task) => + task.status !== 'not_started' && // Filter out tasks with no submissions yet + task.definition.targetGrade <= project.targetGrade, // Filter out tasks that are higher than student's target grade + ), + ]; + } else { + this.filteredTasks = [ + project.tasks.find((t) => t.definition.id === this.selectedTaskDefinition.id), + ]; + } + + this.selectedTask = this.filteredTasks[0] ?? null; + this.project = project; + this.scanningQr = false; + this.loadingStudentData = false; + }) + .catch((e) => { + console.error(e); + this.alertService.error(e, 5000); + this.scanQrCode(); + }) + .finally(() => { + console.timeEnd('getStudentTasks()'); + }); + } +} diff --git a/src/app/projects/states/tutor-notes/tutor-notes.component.html b/src/app/projects/states/tutor-notes/tutor-notes.component.html new file mode 100644 index 0000000000..5d65d88936 --- /dev/null +++ b/src/app/projects/states/tutor-notes/tutor-notes.component.html @@ -0,0 +1,175 @@ +
    + +
    + @if (!loadingTutorNotes) { + @for (note of filteredNotes; track note) { + @if (note.replyToId) { +
    +
    + reply +
    + @if (note.replyTo) { + + Replying to {{ note.replyTo.user.preferredName }} + {{ note.replyTo.user.lastName }} ({{ note.replyTo.user.nickname }}) + + {{ note.replyTo.note }} + } @else { + Replying to: Deleted note + } +
    +
    +
    + } + +
    +
    + @if (note.authorIsMe) { + edit + } + reply + delete +
    + @if (!note.readByUnitRole) { + @if (note.noteIsForMe) { + + } + } @else { +
    Read by tutor
    + } +
    + +
    + + + {{ note.user?.firstName }} {{ note.user?.lastName }} +
    + {{ note.createdAt | humanizedDate }} +
    +
    + +
    + @if (note.taskDefinition) { + {{ note.taskDefinition?.abbreviation }} {{ note.taskDefinition.name }} + } + @if (note.project) { + {{ note.project?.student.name }} + } +
    + + + @if (editingNote && editingNote.id === note.id) { + + Update Note + +
    + + +
    +
    + } @else { +
    + } +
    +
    + } + } @else { + + } +
    + +
    + + All Tasks + @for (option of taskDefinitionFilters; track option) { + + {{ option }} + + } + + + @if (replyingToNote) { +
    +
    + reply +
    + + Replying to {{ replyingToNote.user.firstName }} {{ replyingToNote.user.lastName }} ({{ + replyingToNote.user.nickname + }}) + + {{ replyingToNote.note }} +
    +
    + close +
    + } + + + Tutor note + +
    + +
    +
    +
    +
    diff --git a/src/app/projects/states/tutor-notes/tutor-notes.component.scss b/src/app/projects/states/tutor-notes/tutor-notes.component.scss new file mode 100644 index 0000000000..a6d41ed2d2 --- /dev/null +++ b/src/app/projects/states/tutor-notes/tutor-notes.component.scss @@ -0,0 +1,27 @@ +.mat-icon { + color: #9696969d; + font-size: 20px; + width: 20px; + height: 20px; + cursor: pointer; + vertical-align: middle; + text-align: center; + margin-left: 0.3em; +} + +.mat-icon:hover { + color: black; +} + +@keyframes blueGlowFade { + 0% { + background-color: rgba(66, 133, 244, 0.6); + } + 100% { + background-color: transparent; + } +} + +.flash-highlight { + animation: blueGlowFade 1s ease-out; +} diff --git a/src/app/projects/states/tutor-notes/tutor-notes.component.ts b/src/app/projects/states/tutor-notes/tutor-notes.component.ts new file mode 100644 index 0000000000..2b1543c247 --- /dev/null +++ b/src/app/projects/states/tutor-notes/tutor-notes.component.ts @@ -0,0 +1,217 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import {Task, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; +import {TutorNote} from 'src/app/api/models/tutor-note'; +import {TutorNoteService} from 'src/app/api/services/tutor-note.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-tutor-notes', + templateUrl: './tutor-notes.component.html', + styleUrl: './tutor-notes.component.scss', +}) +export class TutorNotesComponent implements OnInit { + @ViewChild('tutorNotesContainer') tutorNotesContainer!: ElementRef; + @ViewChild('tutorNoteEditor', {static: false}) tutorNoteEditor!: ElementRef; + + @Input() unitRole: UnitRole; + @Input() task: Task; + + loadingTutorNotes: boolean = true; + + noteText: string = ''; + + editingNote?: TutorNote; + editingNoteText?: string = ''; + + replyingToNote?: TutorNote; + + hoveredNoteId: number | null = null; + + constructor( + private userService: UserService, + private tutorNoteService: TutorNoteService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + ) {} + ngOnInit(): void { + if (this.task && !this.unitRole) { + this.unitRole = this.task.tutor; + } + + this.loadingTutorNotes = true; + this.tutorNoteService.loadTutorNotes(this.unitRole).subscribe((notes) => { + this.loadingTutorNotes = false; + this.tutorNoteService.updateTutorNoteReplies(this.unitRole?.tutorNotesCache.currentValues); + this.scrollDown(); + }); + if (this.task) { + this.selectedTaskDefinitions.set(this.task.definition.abbreviation, true); + } else { + this.selectedTaskDefinitions.set('all', true); + } + } + + scrollToComment(commentID: number) { + document.querySelector(`#comment-${commentID}`).scrollIntoView(); + } + + scrollDown() { + setTimeout(() => { + const el = this.tutorNotesContainer.nativeElement; + el.scrollTop = el.scrollHeight; + }, 50); + } + + public submitNote() { + const noteText = this.noteText.trim(); + if (noteText === '') { + return; + } + + this.noteText = ''; + + this.tutorNoteService + .addNote(this.unitRole, noteText, this.task, this.replyingToNote) + .subscribe({ + next: (_note) => { + this.alertService.success('Succesfully submitted note', 4000); + this.scrollDown(); + this.replyingToNote = null; + this.tutorNoteService.updateTutorNoteReplies( + this.unitRole?.tutorNotesCache.currentValues, + ); + }, + error: (error) => { + this.alertService.error(`Failed to create note: ${error}`, 4000); + this.noteText = noteText; + }, + }); + } + + public updateNote() { + const noteText = this.editingNoteText.trim(); + if (noteText === '' || !this.editingNote) { + return; + } + + this.tutorNoteService.updateNote(this.unitRole, this.editingNote, noteText).subscribe({ + next: (_note) => { + this.alertService.success('Succesfully updated note', 4000); + this.editingNote = null; + this.editingNoteText = ''; + }, + error: (error) => { + this.alertService.error(`Failed to update note: ${error}`, 4000); + }, + }); + } + + public markAsRead(note: TutorNote) { + this.tutorNoteService.markAsRead(this.unitRole, note).subscribe({ + next: (response) => { + if (response) { + this.alertService.success(`Marked note as read`, 3000); + } else { + this.alertService.error(`Failed to mark as read`, 6000); + } + }, + error: (error) => { + this.alertService.error(`Failed to mark as read: ${error}`, 6000); + }, + }); + } + + public deleteNote(note: TutorNote) { + this.confirmationModalService.show( + 'Delete note', + 'Are you sure want to delete this tutor note?', + () => { + note.delete(); + }, + ); + } + + public replyToNote(note: TutorNote) { + this.replyingToNote = note; + } + public cancelReplyingToNote() { + this.replyingToNote = null; + } + + public editNote(note: TutorNote) { + if (!note.authorIsMe) { + return; + } + + this.editingNote = note; + this.editingNoteText = note.note; + setTimeout(() => { + this.autoResizeTutorNoteEditor(); + this.tutorNoteEditor?.nativeElement.focus(); + }); + } + + public cancelEditingNote() { + this.editingNote = null; + this.editingNoteText = ''; + } + + public autoResizeTutorNoteEditor() { + const el = this.tutorNoteEditor.nativeElement; + el.style.height = 'auto'; + el.offsetHeight; + el.style.height = el.scrollHeight + 'px'; + } + + scrollToNote(note: TutorNote): void { + const el = document.getElementById(`note-${note.id}`); + if (el) { + el.scrollIntoView({behavior: 'smooth', block: 'center'}); + el.classList.add('flash-highlight'); + setTimeout(() => el.classList.remove('flash-highlight'), 1000); + } + } + + public selectedTaskDefinitions: Map = new Map(); + + public get filteredNotes() { + const selected = this.selectedTaskDefinitions; + const allSelected = selected.size === 0 || selected.get('all'); + + return ( + this.unitRole?.tutorNotesCache?.currentValues?.filter((note) => { + const abbr = note.taskDefinition?.abbreviation; + // if (!abbr) return false; // skip notes without taskDefinition + if (allSelected) return true; + return selected.get(abbr); + }) ?? [] + ); + } + + toggleSelection(option: string) { + if (this.selectedTaskDefinitions.get(option)) { + this.selectedTaskDefinitions.set(option, false); + } else { + this.selectedTaskDefinitions.set(option, true); + } + } + + public get taskDefinitionFilters() { + const abbrs = + this.unitRole.tutorNotesCache.currentValues + .map((note) => note.taskDefinition?.abbreviation) + .filter(Boolean) ?? []; + + // Remove duplicates + return Array.from(new Set(abbrs)); + } + + openProject(event: Event, note: TutorNote) { + event.stopPropagation(); + const link = document.createElement('a'); + link.href = `/projects/${note.project.id}/dashboard/${note.taskDefinition.abbreviation}?tutor=true`; + link.target = '_blank'; + link.click(); + } +} diff --git a/src/app/sessions/states/sign-in/sign-in.component.html b/src/app/sessions/states/sign-in/sign-in.component.html index cf7b12c70c..74fd6b7b99 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.html +++ b/src/app/sessions/states/sign-in/sign-in.component.html @@ -1,55 +1,71 @@
    -
    -
    -
    - Homepage Logo -

    {{ externalName.value }}

    -
    -

    - Welcome to {{ externalName.value }} -

    - - @if (showCredentials) { - - Username - - - } + @if (!isLoading) { +
    +
    +
    + Homepage Logo +

    {{ externalName.value }}

    +
    +

    + Welcome to {{ externalName.value }} +

    + + @if (showCredentials) { + + Username + + + } - @if (showCredentials) { - - Password - - - } - @if (!showCredentials) { - Login via Institution + Password + + + } + @if (!showCredentials) { + + Automatically redirect + + } + + Stay logged in + + - + Sign In + + +
    +
    + } @else if (authMethodFailed) { +
    +
    -
    + }
    diff --git a/src/app/sessions/states/sign-in/sign-in.component.scss b/src/app/sessions/states/sign-in/sign-in.component.scss index da91789cc2..1594f3adc7 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.scss +++ b/src/app/sessions/states/sign-in/sign-in.component.scss @@ -19,3 +19,7 @@ height: 100vh !important; } } + +.custom-md-h-screen { + height: 100vh !important; +} diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index f41b944018..8f047489d4 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -1,10 +1,26 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, Inject, OnInit } from '@angular/core'; -import { StateService, Transition } from '@uirouter/core'; -import { AuthenticationService } from 'src/app/api/services/authentication.service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { GlobalStateService } from 'src/app/projects/states/index/global-state.service'; +import {HttpClient} from '@angular/common/http'; +import {Component, Input, OnInit} from '@angular/core'; +import {StateService, Transition} from '@uirouter/core'; +import {BehaviorSubject} from 'rxjs'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; + +// Add fallback to check url for query parameters +interface IParams { + [key: string]: string; +} + +const paramReducer = (params: IParams, pair: string): IParams => { + const [key, value] = `${pair}=`.split('=').map(decodeURIComponent); + + return key.length > 0 ? {...params, [key]: value} : params; +}; + +const getUrlParams = (search: string): IParams => + `${search}?`.split('?')[1].split('&').reduce(paramReducer, {}); type signInData = | { @@ -27,16 +43,27 @@ type signInData = styleUrls: ['./sign-in.component.scss'], }) export class SignInComponent implements OnInit { - signingIn: boolean; - showCredentials = false; - invalidCredentials: boolean; - api: string; - SSOLoginUrl: any; - authMethodLoaded: boolean; - externalName: any; - formData: signInData; + public signingIn: boolean; + public showCredentials: boolean = false; + public invalidCredentials: boolean; + public api: string; + public SSOLoginUrl: string; + public authMethodLoaded: boolean; + public externalName: BehaviorSubject; + public formData: signInData; + public isLoading: boolean = true; + public authMethodFailed: boolean = false; + + // Get query params from the resolve in the router state + @Input() username: string; + @Input() authToken: string; + @Input() ltiToken: string; + @Input() ltik: string; + @Input() isLtiLogin: boolean; + constructor( private authService: AuthenticationService, + private userService: UserService, private state: StateService, private constants: DoubtfireConstants, private http: HttpClient, @@ -46,60 +73,141 @@ export class SignInComponent implements OnInit { ) {} ngOnInit(): void { + this.authService.afterAuthCall((result) => { + if (result) { + const params = getUrlParams(document.location.href); + this.isLoading = false; + + if (params.isLtiLogin && params.ltik) { + this.globalState.hideHeader(); + this.userService.currentUser.ltik = params.ltik; + return this.state.go('lti', { + ltik: params.ltik, + }); + } else { + this.globalState.goHome(); + return this.state.go('welcome'); + } + } + this.isLoading = true; + }); + + this.globalState.onLoad(() => this.initAfterGlobalLoad()); + } + + private initAfterGlobalLoad(): void { + if (!this.isLoading) { + // return out if we're already redirecting elsewhere in the afterAuthCall + return; + } + this.formData = { username: '', password: '', - remember: false, - autoLogin: localStorage.getItem('autoLogin') ? true : false, + remember: this.authService.rememberMe, + autoLogin: this.autoLogin, }; // Check for SSO this.globalState.hideHeader(); this.api = this.constants.API_URL; this.externalName = this.constants.ExternalName; + // HACK: Workaround the fact that query params do not work in Safari with ui-router + const params = getUrlParams(document.location.href); + if (!this.username) { + this.username = this.transition.params().username || params.username; + this.authToken = this.transition.params().authToken || params.authToken; + } + + this.ltiToken = params.ltiToken ?? undefined; + this.ltik = params.ltik ?? undefined; + this.isLtiLogin = params.isLtiLogin?.toLowerCase() === 'true' ? true : false; + // wait 2 seconds with rxjs - const wait = new Promise((resolve) => setTimeout(resolve, 2000)); - this.http.get(`${this.constants.API_URL}/auth/method`).subscribe((response: any) => { - // if there is a string in response.data.redirect_to - this.SSOLoginUrl = response.redirect_to || false; - - if (this.SSOLoginUrl) { - if (this.transition.params().authToken) { - // This is SSO and we just got an auth_token? Must request to sign in + const wait = new Promise((resolve) => setTimeout(resolve, 3000)); + this.http.get(`${this.constants.API_URL}/auth/method`).subscribe({ + next: (response: any) => { + this.isLoading = false; + + // if there is a string in response.data.redirect_to + this.SSOLoginUrl = response.redirect_to || false; + + if (this.authToken) { + // We have an auth token - so attempt to convert to access token return this.signIn({ - auth_token: this.transition.params().authToken, - username: this.transition.params().username, - remember: true, - }); - } else if (this.formData.autoLogin) { - return wait.then(() => { - // Double check in case changed in the meantime - if (this.formData.autoLogin) { - this.redirectToSSO(); - } + auth_token: this.authToken, + username: this.username, + remember: this.authService.rememberMe, }); + } else if (this.ltiToken) { + // We have a signed Lti token containing user data + // Forward it to the API and request a one time auth token + this.signingIn = true; + + this.authService + .signInWithLti({ + ltik: this.ltik, + lti_token: this.ltiToken, + }) + .subscribe({ + next: () => { + // this.globalState.goHome(); + // this.actionSignInSuccess(); + }, + error: (err) => { + this.signingIn = false; + this.formData.password = ''; + this.invalidCredentials = true; + this.alerts.error(err, 6000); + }, + }); + } else if (this.SSOLoginUrl) { + if (this.autoLogin) { + return wait.then(() => { + // Double check in case changed in the meantime + if (this.autoLogin) { + this.redirectToSSO(); + } + }); + } else { + this.globalState.isLoadingSubject.next(false); + // We are SSO and no credentials + this.showCredentials = false; + return wait.then(); + } } else { - // We are SSO and no credentials - this.showCredentials = false; + this.globalState.isLoadingSubject.next(false); + this.authMethodLoaded = true; + this.showCredentials = true; return wait.then(); } - } else { - this.authMethodLoaded = true; - this.showCredentials = true; - return wait.then(); - } - }), - function (err) { + }, + error: (err) => { this.authMethodFailed = true; - this.error = err; + // this.error = err; - // return after waiting 1500 with the wait promise + // return after waiting with the wait promise return wait.then(); - }; + }, + }); + } - if (this.authService.isAuthenticated()) { - this.state.go('home'); - } + public get autoLogin(): boolean { + // Check if autoLogin is set in localStorage + return localStorage.getItem('autoLogin') === 'true'; + } + + public set autoLogin(value: boolean) { + // Set autoLogin in localStorage + localStorage.setItem('autoLogin', value ? 'true' : 'false'); + } + + /** + * Perform the actions needed when the user successfully signs in. + */ + private actionSignInSuccess(): void { + this.globalState.loadGlobals(); + this.state.go('welcome'); } /** @@ -107,7 +215,7 @@ export class SignInComponent implements OnInit { */ private redirectToSSO(): void { if (this.SSOLoginUrl) { - if (this.formData.autoLogin) { + if (this.autoLogin) { localStorage.setItem('autoLogin', 'true'); } else { localStorage.removeItem('autoLogin'); @@ -117,17 +225,35 @@ export class SignInComponent implements OnInit { } } - signIn(signInCredentials: signInData): void { + /** + * Sign in using the provided credentials. For SSO, this will redirect to the SSO login URL + * if the auth token is not provided. Then when the api redirects hack to us, with the auth token, + * we will then use the passed login auth token to get an access token.#form + * + * For all logins, if rememberMe is set, the api will also send a secure cookie + * with the refresh token. This will be used to get an access token when the user + * refreshes the page / returns to the app / etc. + */ + public signIn(signInCredentials: signInData): void { + // Redirect to SSO if we do not have an auth token already (from SSO callback) if (this.SSOLoginUrl && !signInCredentials.auth_token) { return this.redirectToSSO(); } - signInCredentials.remember = true; + // Indicate we are signing in... this.signingIn = true; this.authService.signIn(signInCredentials).subscribe({ next: () => { - this.state.go('home'); + if (this.isLtiLogin) { + this.globalState.loadGlobals(); + const params = getUrlParams(document.location.href); + this.state.go('lti', { + ltik: params.ltik, + }); + } else { + this.actionSignInSuccess(); + } }, error: (err) => { this.signingIn = false; diff --git a/src/app/sessions/transition-hooks.service.ts b/src/app/sessions/transition-hooks.service.ts index 218e0c5397..949e312f31 100644 --- a/src/app/sessions/transition-hooks.service.ts +++ b/src/app/sessions/transition-hooks.service.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@angular/core'; -import { TransitionService } from '@uirouter/angular'; -import { UserService } from '../api/services/user.service'; -import { DoubtfireAngularModule } from '../doubtfire-angular.module'; -import { GlobalStateService } from '../projects/states/index/global-state.service'; -import { DoubtfireConstants } from '../config/constants/doubtfire-constants'; +import {Injectable} from '@angular/core'; +import {TransitionService} from '@uirouter/angular'; +import {UserService} from '../api/services/user.service'; +import {DoubtfireAngularModule} from '../doubtfire-angular.module'; +import {GlobalStateService} from '../projects/states/index/global-state.service'; +import {DoubtfireConstants} from '../config/constants/doubtfire-constants'; +import {AuthenticationService} from '../api/services/authentication.service'; /** * The TransitionHooksService is responsible for intercepting transitions between states. @@ -20,7 +21,8 @@ export class TransitionHooksService { private userService: UserService, private transitions: TransitionService, private globalState: GlobalStateService, - private constants: DoubtfireConstants + private constants: DoubtfireConstants, + private authenticationService: AuthenticationService, ) { // Get the tii settings... this.constants.IsTiiEnabled.subscribe((enabled) => { @@ -29,8 +31,12 @@ export class TransitionHooksService { // Hook into "onBefore" to check transitions before they occur this.transitions.onBefore({}, (transition) => { + // log all possible states + // console.log(transition.router.stateRegistry.get()) + // Where is the transition coming from and going to? const toState = transition.to().name; + const toStateData = transition.to().data; // const fromState = transition.from().name; // Setup the global state @@ -43,15 +49,19 @@ export class TransitionHooksService { // Adjust settings such as headers switch (toState) { case 'timeout': + case 'success-close': return true; case 'sign_in': this.globalState.hideHeader(); break; case 'welcome': - // block acess to welcome once run - if (this.userService.currentUser.hasRunFirstTimeSetup || this.userService.isAnonymousUser()) { - return false; + if ( + authenticationService.isAuthenticated() && + userService.currentUser.hasRunFirstTimeSetup + ) { + return transition.router.stateService.target('home'); } + this.globalState.hideHeader(); break; case 'home': @@ -61,26 +71,46 @@ export class TransitionHooksService { break; } - // Redirect to welcome if user has not run first time setup - if ( - !this.userService.isAnonymousUser() && - !userService.currentUser.hasRunFirstTimeSetup && - toState !== 'welcome' - ) { - return transition.router.stateService.target('welcome'); - } + // After auth... check the following + this.authenticationService.afterAuthCall(() => { + // Check authorization whitelist + if ( + toStateData.roleWhitelist && + !this.authenticationService.isAuthorised(toStateData.roleWhitelist) + ) { + if (authenticationService.isAuthenticated()) { + return transition.router.stateService.go('unauthorised'); + } else if (toState !== 'sign_in') { + return transition.router.stateService.go('sign_in'); + } + } + // Redirect to welcome if user has not run first time setup + if ( + !this.userService.isAnonymousUser() && + !userService.currentUser.hasRunFirstTimeSetup && + toState !== 'welcome' + ) { + return transition.router.stateService.go('welcome'); + } - // Redirect to eula if user has not accepted eula - // they are loged in, have run first time setup, - // but not accepted eula - if ( this.tiiEnabled && - !this.userService.isAnonymousUser() && - userService.currentUser.hasRunFirstTimeSetup && - !userService.currentUser.acceptedTiiEula && - toState !== 'eula' - ) { - return transition.router.stateService.target('eula'); - } + // Block access to welcome after account setup + if (userService.currentUser.hasRunFirstTimeSetup && toState === 'welcome') { + return transition.router.stateService.go('home'); + } + + // Redirect to eula if user has not accepted eula + // they are loged in, have run first time setup, + // but not accepted eula + if ( + this.tiiEnabled && + !this.userService.isAnonymousUser() && + userService.currentUser.hasRunFirstTimeSetup && + !userService.currentUser.acceptedTiiEula && + toState !== 'eula' + ) { + return transition.router.stateService.go('eula'); + } + }); }); } diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html new file mode 100644 index 0000000000..131bc86541 --- /dev/null +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html @@ -0,0 +1,46 @@ +

    Request Feedback Review

    + +

    + If you believe the feedback or marking on this task does not accurately reflect your work, you + may request a review. This allows another tutor to reassess the feedback and determine whether + it should be confirmed or revised. +

    + +

    + You have + + {{ task.project.escalationAttemptsRemaining }} review request{{ + task.project.escalationAttemptsRemaining !== 1 ? 's' : '' + }} + + remaining for this unit. If the original feedback is revised as a result of this review, the + request will not be counted against your remaining total. +

    + + + Reason for review request + +
    + {{ reviewComment?.length || 0 }}/1000 +
    +
    +

    Review decisions are final once resolved.

    + + + + + +
    diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.scss b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts new file mode 100644 index 0000000000..d44c1853ca --- /dev/null +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts @@ -0,0 +1,57 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Task} from 'src/app/api/models/task'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {FeedbackAppealModalData} from './feedback-appeal-modal.service'; +import {TaskService} from 'src/app/api/services/task.service'; + +@Component({ + selector: 'f-feedback-appeal-modal', + templateUrl: './feedback-appeal-modal.component.html', + styleUrl: './feedback-appeal-modal.component.scss', +}) +export class FeedbackAppealModalComponent implements OnInit { + task: Task; + + reviewComment: string; + submitting: boolean; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: FeedbackAppealModalData, + private alerts: AlertService, + private taskService: TaskService, + ) {} + + ngOnInit() { + this.task = this.data.task; + } + + submit(): void { + this.submitting = true; + this.task.requestFeedbackReview().subscribe({ + next: (_response) => { + this.alerts.success( + `Requested feedback review for ${this.task.definition.abbreviation} ${this.task.definition.name}`, + 3000, + ); + setTimeout(() => { + // Fetch the "Feedback Review Requested" comment + this.taskService.notifyStatusChange(this.task); + setTimeout(() => { + this.task.addComment(this.reviewComment); + }, 250); + this.dismissModal(); + }, 250); + }, + error: (error) => { + this.alerts.error(`An error occurred: ${error}`, 3000); + this.submitting = false; + }, + }); + } + + public dismissModal() { + this.dialogRef.close(); + } +} diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service.ts b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service.ts new file mode 100644 index 0000000000..622d3bf99f --- /dev/null +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service.ts @@ -0,0 +1,29 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {Task} from 'src/app/api/models/task'; +import {FeedbackAppealModalComponent} from './feedback-appeal-modal.component'; + +export interface FeedbackAppealModalData { + task: Task; +} + +@Injectable({ + providedIn: 'root', +}) +export class FeedbackAppealModalService { + constructor(public dialog: MatDialog) {} + + public show(task: Task) { + const _dialogRef = this.dialog.open( + FeedbackAppealModalComponent, + { + data: { + task: task, + }, + position: {top: '2.5%'}, + width: '100%', + maxWidth: '700px', + }, + ); + } +} diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html index 0906d7b593..7fa8e7055e 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html @@ -1,27 +1,27 @@ -
    - - - -
    +
    + + + +
    diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html new file mode 100644 index 0000000000..fbd3164016 --- /dev/null +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html @@ -0,0 +1,65 @@ +

    Select submission type

    + +

    + This task won't be marked as complete by your tutor. It will be assessed as part of your final + portfolio. +

    +

    + You can submit it for feedback before the deadline, but you'll need to resubmit it later for + portfolio assessment. +

    +
    + + +
    + @if (selectedTransition === 'ready_for_feedback') { +

    + You've made progress on this task and would like feedback, clarification, or to discuss + questions with your tutor. +

    +

    + If submitted before the deadline, your tutor will review it and provide feedback. After making + changes, you'll need to resubmit it before the portfolio deadline, using the + I’m done! button. +

    + } @else if (selectedTransition === 'assess_in_portfolio') { +

    + You’re done with this task and satisfied with your submission. You don’t require any further + feedback. +

    +

    + This submission will not be reviewed again by your tutor and will be assessed directly in your + final portfolio. You can resubmit as many times as you like until the portfolio deadline. +

    + } +
    + + + + diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.scss b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.scss new file mode 100644 index 0000000000..50781aeafa --- /dev/null +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.scss @@ -0,0 +1,6 @@ +.icon-size { + font-size: 35px; + height: 35px; + width: 35px; + margin: 0; +} diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts new file mode 100644 index 0000000000..71a5bb4268 --- /dev/null +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts @@ -0,0 +1,47 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Task} from 'src/app/api/models/task'; +import {TaskStatusEnum} from 'src/app/api/models/task-status'; + +export interface SubmissionTypeModalData { + task: Task; +} + +@Component({ + selector: 'f-submission-type-modal', + templateUrl: './submission-type-modal.component.html', + styleUrls: ['./submission-type-modal.component.scss'], +}) +export class SubmissionTypeModalComponent { + selectedTransition: 'ready_for_feedback' | 'assess_in_portfolio' = null; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: SubmissionTypeModalData, + private dialogRef: MatDialogRef, + ) {} + + public selectRff() { + this.selectedTransition = 'ready_for_feedback'; + } + + public selectAip() { + this.selectedTransition = 'assess_in_portfolio'; + } + + public submit() { + if (this.selectedTransition === null) { + return; + } + + this.triggerTransition(this.selectedTransition); + } + + private triggerTransition(status: TaskStatusEnum) { + this.data.task.triggerTransition(status); + this.dismissModal(); + } + + private dismissModal() { + this.dialogRef.close(); + } +} diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.service.ts b/src/app/tasks/modals/submission-type-modal/submission-type-modal.service.ts new file mode 100644 index 0000000000..1c0ab250c8 --- /dev/null +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.service.ts @@ -0,0 +1,29 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import { + SubmissionTypeModalComponent, + SubmissionTypeModalData, +} from './submission-type-modal.component'; +import {Task} from 'src/app/api/models/task'; + +@Injectable({ + providedIn: 'root', +}) +export class SubmissionTypeModalService { + constructor(public dialog: MatDialog) {} + + public show(task: Task) { + const _dialogRef = this.dialog.open( + SubmissionTypeModalComponent, + { + autoFocus: false, + data: { + task: task, + }, + position: {top: '2.5%'}, + width: '100%', + maxWidth: '700px', + }, + ); + } +} diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index b9c9ebd2b9..a310b31abf 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -32,7 +32,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) UploadSubmissionModal ) -.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> +.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, newTaskService, newProjectService, task, reuploadEvidence, PrivacyPolicy, alertService, emojiService) -> $scope.privacyPolicy = PrivacyPolicy # Expose task to scope $scope.task = task @@ -68,21 +68,31 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) start: null # initialised by uploader onBeforeUpload: -> $scope.uploader.payload.contributions = mapTeamToPayload() if _.includes(states.shown, 'group') - $scope.uploader.payload.alignment_data = mapAlignmentDataToPayload() if _.includes(states.shown, 'alignment') $scope.uploader.payload.trigger = 'need_help' if $scope.submissionType == 'need_help' + $scope.uploader.payload.trigger = 'assess_in_portfolio' if $scope.submissionType == 'assess_in_portfolio' || $scope.task.status == 'assess_in_portfolio' + if $scope.comment? and $scope.comment.trim() isnt '' + $scope.uploader.payload.comment = emojiService.nativeEmojiToColons($scope.comment) onSuccess: (response) -> - $scope.uploader.response = response - if $scope.task.isTestSubmission - newProjectService.loadProject(response.project_id, $scope.task.unit).subscribe({ - next: (response) -> - $scope.task.project = response - }) + # Ensure our response contains the data we're expecting + if typeof response is 'object' and response? and response.id? and response.project_id? and response.status? + $scope.uploader.response = response + if $scope.task.isTestSubmission + newProjectService.loadProject(response.project_id, $scope.task.unit).subscribe({ + next: (response) -> + $scope.task.project = response + }) + else + console.error "Invalid response", response + $modalInstance.close(task) + alertService.error("Upload failed. Please try again, or contact your tutor if the issue continues.", 8000) + onFailureCancel: $modalInstance.dismiss onComplete: -> + return unless $scope.uploader.response? and $scope.uploader.response.id? $modalInstance.close(task) - unless $scope.task.isTestSubmission + # unless $scope.task.isTestSubmission # Add comment if requested - task.addComment($scope.comment) if $scope.comment.trim().length > 0 + # task.addComment($scope.comment) if $scope.comment.trim().length > 0 # Broadcast that upload is complete $rootScope.$broadcast('TaskSubmissionUploadComplete', task) # Perform as timeout to show 'Upload Complete' @@ -100,7 +110,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) # States functionality states = { # All possible states - all: ['group', 'files', 'alignment', 'comments', 'uploading'] + all: ['group', 'files', 'comments', 'uploading'] # Only states which are shown (populated in initialise) shown: [] # The currently active state (set in initialise) @@ -124,9 +134,8 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) isRFF = $scope.submissionType == 'ready_for_feedback' isTestSubmission = $scope.submissionType == 'test_submission' removed = [] - # Remove group and alignment states + # Remove group states removed.push('group') if !isRFF || !task.isGroupTask() - removed.push('alignment') if !isRFF || !task.unit.ilos.length > 0 removed.push('comments') if isTestSubmission removed # Initialises the states @@ -161,11 +170,6 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) # Disable group if group members not allocated anything group: -> _.chain($scope.team.memberContributions).map('confRating').compact().value().length == 0 - # Disable alignment if no alignments made (need at least 1) and - # if description is blank - alignment: -> - _.chain($scope.alignments).map('rating').compact().value().length == 0 || - $scope.alignmentsRationale.trim().length == 0 # Disable files if no files made files: -> !$scope.uploader.isReady @@ -174,8 +178,8 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) back: -> false submit: -> - # Disable if no comment is supplied with need_help - !$scope.uploader.isReady || ($scope.comment.trim().length == 0 && $scope.submissionType == 'need_help') + # Disable if no comment is supplied with need_help, or if submitting for feedback and task is assess in portfolio only + !$scope.uploader.isReady or ($scope.comment.trim().length < 25 && ((($scope.submissionType == 'ready_for_feedback' || $scope.submissionType == 'reupload_evidence') && $scope.task.definition.assessInPortfolioOnly) || $scope.submissionType == 'need_help') ) cancel: -> # Can't cancel whilst uploading $scope.uploader.isUploading @@ -223,44 +227,4 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) # Comment on the task $scope.comment = "" - - # Maps the alignment data to payload data - mapAlignmentDataToPayload = -> - _.chain($scope.alignments) - .map((alignment, key) -> - alignment.rationale = $scope.alignmentsRationale - alignment.ilo_id = +key - alignment - ) - .filter((alignment) -> - alignment.rating > 0 - ) - .value() - - unless $scope.task.isTestSubmission - # Get initial alignment data... - initialAlignments = task.project.taskOutcomeAlignments.filter( (a) -> a.taskDefinition.id == task.definition.id ) - # ILO alignment defaults - $scope.alignmentsRationale = if initialAlignments.length > 0 then initialAlignments[0].description else "" - staffAlignments = $scope.task.staffAlignments() - $scope.ilos = _.map(task.unit.ilos, (ilo) -> - staffAlignment = _.find(staffAlignments, (sa) -> sa.learningOutcome.id == ilo.id) - staffAlignment ?= {} - staffAlignment.rating ?= 0 - staffAlignment.label = outcomeService.alignmentLabels[staffAlignment.rating] - ilo.staffAlignment = staffAlignment - ilo - ) - $scope.alignments = _.chain(task.unit.ilos) - .map((ilo) -> - value = initialAlignments.filter((a) -> a.learningOutcome.id == ilo.id)?[0]?.rating - value ?= 0 - [ilo.id, {rating: value }] - ) - .fromPairs() - .value() - else - $scope.ilos = [] - $scope.alignments = [] - $scope.alignmentsRationale = "" ) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 9caab7897e..bfda995467 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -78,86 +78,30 @@

    -
    -
    -
    -

    - Learning Outcome Alignment * -

    -

    - Please rate the relevancy of this task to the specific learning outcome. - You must relate this task to at least one outcome and provide a rationale to proceed. -

    -

    - If you think the task is not related to a specific outcome, click the highest filled circle to remove its relevancy. -

    -
    - -
    -
    -
    -

    - {{ilo.abbreviation}} - {{ilo.name}} -

    -
    Staff believe that {{ilo.staffAlignment.label | lcfirst}}. Click to expand.
    -
    -
    -

    -

    Outcome Description
    -
    -

    -

    -

    Rationale
    -
    -

    -
    -
    -
    -
    - - -
    -
    -
    - -
    -
    -
    -

    - What do you need help with? -

    -

    - Final comments -

    - +
    +

    What do you need help with?

    + Supply a comment on what you would like help on for this task so your tutor can assist you. - +
    +
    +

    Final comments

    + + Please supply a comment specifying which areas of your submission you would like feedback on. + + Supply an optional comment about this submission for your tutor to read as they assess.
    - +
    Character count: {{comment.length}} (Min. 25)
    @@ -196,7 +140,7 @@

    Plagiarism and Collusion

    - diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.html b/src/app/tasks/task-comment-composer/task-comment-composer.component.html index 448f88f46c..c589c6f17e 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.html +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.html @@ -11,21 +11,19 @@ @if (task) {
    -
    -
    - Replying to: - {{ originalComment !== null ? originalComment.author.name : '' }} - -
    -

    {{ originalComment !== null ? originalComment.text : '' }}

    +
    + + Replying to: + {{ originalComment !== null ? originalComment.author.name : '' }}
    +

    {{ originalComment !== null ? originalComment.text : '' }}

    } @@ -50,10 +48,18 @@
    + @if (task) { + + }
    @@ -140,7 +146,7 @@
    +
    + + task +
    diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.scss b/src/app/tasks/task-comment-composer/task-comment-composer.component.scss index a79e6a5be4..d83ccd18a0 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.scss +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.scss @@ -64,6 +64,36 @@ $emoji-color: lighten( } } + +#textField.draft-loaded { + animation: draftFadeIn 0.3s ease-in; +} + +@keyframes draftFadeIn { + from { opacity: 0.5; background-color: rgba(0, 0, 255, 0.05); } + to { opacity: 1; background-color: transparent; } +} + +.draft-loaded { + animation: blueGlowFade 1.5s ease; + border-radius: 4px; +} + +@keyframes blueGlowFade { + 0% { + background-color: rgba(66, 133, 244, 0.2); + box-shadow: 0 0 8px 2px rgba(66, 133, 244, 0.6); + } + 70% { + background-color: rgba(66, 133, 244, 0.1); + box-shadow: 0 0 6px 1px rgba(66, 133, 244, 0.3); + } + 100% { + background-color: transparent; + box-shadow: none; + } +} + #innerButtons { align-items: flex-end; display: flex; diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts index 9a4a3297ea..294f305292 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts @@ -1,31 +1,47 @@ +import {animate, style, transition, trigger} from '@angular/animations'; import { + AfterViewInit, + ChangeDetectorRef, Component, - OnInit, + DoCheck, + ElementRef, Inject, Input, - ViewChildren, - QueryList, - KeyValueDiffers, KeyValueDiffer, - ElementRef, + KeyValueDiffers, + OnChanges, + OnInit, + QueryList, + SimpleChanges, ViewChild, - DoCheck, + ViewChildren, } from '@angular/core'; -import {trigger, style, animate, transition} from '@angular/animations'; -import {analyticsService} from 'src/app/ajs-upgraded-providers'; -import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {EmojiSearch} from '@ctrl/ngx-emoji-mart'; import {EmojiData} from '@ctrl/ngx-emoji-mart/ngx-emoji/'; +import {BehaviorSubject, Subscription} from 'rxjs'; +import {analyticsService} from 'src/app/ajs-upgraded-providers'; +import { + FeedbackTemplate, + Task, + TaskComment, + TaskCommentService, +} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; import {EmojiService} from 'src/app/common/services/emoji.service'; -import {Task, TaskComment, TaskCommentService} from 'src/app/api/models/doubtfire-model'; import {TaskCommentsViewerComponent} from '../task-comments-viewer/task-comments-viewer.component'; -import {BehaviorSubject} from 'rxjs'; -import {AlertService} from 'src/app/common/services/alert.service'; + +interface ApiError { + error?: string; + message?: string; + status?: number; +} /** * The task comment viewer needs to share data with the Task Comment Composer. The data needed * id defined through this interface. */ + export interface TaskCommentComposerData { originalComment: TaskComment; } @@ -55,17 +71,22 @@ const ACCEPTED_FILE_TYPES = [ styleUrls: ['./task-comment-composer.component.scss'], animations: [ trigger('shrinkgrow', [ - // 38.4 and 80 are the precise sizes of the buttons to the left of the input field transition('true => false', [style({width: 38.4}), animate('150ms 0ms ease-in-out')]), transition('false => true', [style({width: 80}), animate('150ms 0ms ease-in-out')]), ]), ], }) -export class TaskCommentComposerComponent implements DoCheck { +export class TaskCommentComposerComponent implements OnInit, AfterViewInit, DoCheck, OnChanges { @Input() task: Task; @Input() sharedData: TaskCommentComposerData; public $userIsTyping = new BehaviorSubject(false); + private draftSaveSubscription = new Subscription(); + private readonly DRAFT_KEY_PREFIX = 'task_comment_draft_'; + public isDraftLoaded = false; + private submittedTaskIds: Set = new Set(); + + public isSending: boolean = false; comment = { text: '', @@ -77,11 +98,12 @@ export class TaskCommentComposerComponent implements DoCheck { @ViewChild('uploader') uploader: ElementRef; differ: KeyValueDiffer; - showEmojiPicker: boolean = false; - emojiSearchMode: boolean = false; + showEmojiPicker = false; + emojiSearchMode = false; emojiRegex: RegExp = /(?:\:)(.*?)(?=\:|$)/; emojiSearchResults: EmojiData[] = []; emojiMatch: string; + showFeedbackTemplatePicker: boolean = false; recording = false; cagStartWidth: number; @@ -94,8 +116,202 @@ export class TaskCommentComposerComponent implements DoCheck { @Inject(analyticsService) private analytics, private alerts: AlertService, @Inject(TaskCommentService) private taskCommentService: TaskCommentService, + private cdRef: ChangeDetectorRef, ) { this.differ = this.differs.find({}).create(); + // submitted tasks from sessionStorage + try { + const saved = sessionStorage.getItem('task_comments_submitted'); + if (saved) { + this.submittedTaskIds = new Set(JSON.parse(saved)); + } + } catch (e) { + console.error('Error loading submitted tasks:', e); + } + } + + ngOnInit() {} + + ngOnChanges(changes: SimpleChanges) { + this.showFeedbackTemplatePicker = false; + + if (changes.task && changes.task.currentValue !== changes.task.previousValue) { + const newTask = changes.task.currentValue as Task; + // Check if the task has changed + + this.cancelReply(); + + this.clearInput(); + + if (newTask) { + this.loadDraftForTask(newTask); + } + } + } + + ngAfterViewInit() { + setTimeout(() => { + if (this.task?.id) { + this.loadDraftForTask(this.task); + } + }, 100); + } + + // ngOnDestroy() { + // if (this.task?.id) { + // try { + // const inputElement = this.input?.first?.nativeElement; + // if (inputElement) { + // const text = inputElement.innerText.trim(); + // if (text && !this.hasSubmittedComment) { + // localStorage.setItem(this.getDraftKey(this.task), text); + // } else { + // } + // } + // } catch (error) {} + // } + // } + + // Update onInputChange to reset submitted status + onInputChange(event: Event) { + const target = event.target as HTMLElement; + const text = target.innerText; + const raw = target.innerText; + + // If user is typing something new after submission, reset the submitted status + if (this.task) { + const taskKey = + this.task.id || + `${this.task.projectId || this.task.project?.id}_${this.task.definition?.id}`; + + // If this was a previously submitted task and user is typing again, + // remove from submitted set + if (this.submittedTaskIds.has(taskKey) && text.trim()) { + this.submittedTaskIds.delete(taskKey); + + // Update session storage + try { + sessionStorage.setItem( + 'task_comments_submitted', + JSON.stringify([...this.submittedTaskIds]), + ); + } catch (e) { + console.error('Error saving submitted tasks:', e); + } + } + + const draftKey = this.getDraftKey(this.task); + // this.taskDraftContents.set(draftKey, raw); + } + + this.saveCurrentDraft(); + } + + private getDraftKey(task: Task): string { + // If task has an ID, use it + if (task.id) { + return `${this.DRAFT_KEY_PREFIX}${task.id}`; + } + + // For "not started" tasks, create a composite key using only valid properties + const projectId = task.projectId || task.project?.id || 'unknown'; + // Fix: Use task.definition.id instead of task.definition_id + const definitionId = task.definition?.id || 'unknown'; + + return `${this.DRAFT_KEY_PREFIX}${projectId}_${definitionId}`; + } + + private hasContent(raw: string): boolean { + return raw.replace(/\s+/g, '').length > 0; + } + + // Update saveDraftForTask to use the taskDraftContents map + private saveDraftForTask(task: Task, rawFromDom?: string): void { + if (!task) { + return; + } + + const draftKey = this.getDraftKey(task); + + try { + let raw: string; + if (this.task?.id === task.id && this.input.first) { + raw = this.input.first.nativeElement.innerText; + } else { + // raw = this.taskDraftContents.get(draftKey) ?? ''; + } + + if (!this.hasContent(raw)) { + // No text to save, removing draft from localStorage + // this.taskDraftContents.delete(draftKey); + localStorage.removeItem(draftKey); + return; + } + + const text = raw.trim(); + // Save comment draf + // this.taskDraftContents.set(draftKey, text); + localStorage.setItem(draftKey, text); + } catch (error) { + console.error('saveDraftForTask error:', error); + } + } + + private loadDraftForTask(task: Task) { + if (!task) { + return; + } + + const taskKey = task.id || `${task.projectId || task.project?.id}_${task.definition?.id}`; + + if (this.submittedTaskIds.has(taskKey)) { + return; + } + + const draftKey = this.getDraftKey(task); + try { + const draft = localStorage.getItem(draftKey); + + if (!draft) { + return; + } + + const maxRetries = 5; + const retryWithTimeout = (attempt = 0) => { + if (!this.input || !this.input.first || !this.input.first.nativeElement) { + if (attempt < maxRetries) { + setTimeout(() => retryWithTimeout(attempt + 1), 200); + return; + } else { + return; + } + } + + this.input.first.nativeElement.innerText = draft; + // this.taskDraftContents.set(draftKey, draft); + this.isDraftLoaded = true; + this.cdRef.detectChanges(); + + setTimeout(() => { + this.isDraftLoaded = false; + this.cdRef.detectChanges(); + }, 1500); + }; + + retryWithTimeout(); + } catch (error) {} + } + + private clearInput() { + if (this.input?.first?.nativeElement) { + this.input.first.nativeElement.innerText = ''; + this.cdRef.detectChanges(); + } + } + + private saveCurrentDraft() { + if (!this.task) return; + this.saveDraftForTask(this.task); } ngDoCheck() { @@ -242,6 +458,21 @@ export class TaskCommentComposerComponent implements DoCheck { ].join(''); } + addFeedback(template: FeedbackTemplate): void { + const char = template.commentText; + const text = this.input.first.nativeElement.innerText; + const position = this.caretOffset(); + this.input.first.nativeElement.innerText = [ + text.slice(0, position), + char, + text.slice(position), + ].join(''); + this.input.first.nativeElement.focus(); + setTimeout(() => { + this.saveDraftForTask(this.task); + }); + } + openDiscussionComposer() { this.dialog.open(DiscussionComposerDialog, { data: { @@ -259,20 +490,48 @@ export class TaskCommentComposerComponent implements DoCheck { } addComment() { + if (this.isSending) { + return; + } + this.isSending = true; + const originalComment = this.sharedData.originalComment; if (originalComment != null) { this.cancelReply(); } + const text = this.emojiService.nativeEmojiToColons(this.input.first.nativeElement.innerText); - this.taskCommentService.addComment(this.task, text, 'text', originalComment).subscribe( - (tc: TaskComment) => { + const taskKey = + this.task.id || `${this.task.projectId || this.task.project?.id}_${this.task.definition?.id}`; + + const draftKey = this.getDraftKey(this.task); + this.taskCommentService.addComment(this.task, text, 'text', originalComment).subscribe({ + next: (_tc: TaskComment) => { + this.isSending = false; + + this.submittedTaskIds.add(taskKey); + + try { + sessionStorage.setItem( + 'task_comments_submitted', + JSON.stringify([...this.submittedTaskIds]), + ); + } catch (e) { + console.error('Error saving submitted tasks:', e); + } + + if (this.task) { + localStorage.removeItem(draftKey); + } + this.input.first.nativeElement.innerText = ''; }, - (error: any) => { - this.alerts.error(error || error?.message, 2000); + error: (error: ApiError) => { + this.isSending = false; + this.alerts.error(error.error || error.message || `Failed to add comment: ${error}`, 6000); }, - ); + }); } addCommentWithType(comment: string, type: string) { @@ -316,6 +575,11 @@ export class TaskCommentComposerComponent implements DoCheck { }, ); } + + showFeedbackPicker() { + this.showFeedbackTemplatePicker = !this.showFeedbackTemplatePicker; + this.commentsViewer.scrollDown(); + } } // The discussion prompt composer dialog Component @@ -328,7 +592,7 @@ export class TaskCommentComposerComponent implements DoCheck { export class DiscussionComposerDialog implements OnInit { constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, + @Inject(MAT_DIALOG_DATA) public data: {task: Task}, ) {} ngOnInit() {} diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html new file mode 100644 index 0000000000..323a2e0eed --- /dev/null +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html @@ -0,0 +1,145 @@ + + + + + + + + search + + +
    +
    +
    + + check_circle + {{ template.chipText }} + +
    +
    + +
    +
    +
    + {{ item.outcome.abbreviation }} - {{ item.outcome.shortDescription }} +
    +
    + + check_circle + + folder + chevron_right + {{ template.chipText }} + +
    +
    +
    + +
    +
    +
    + {{ item.outcome.abbreviation }} - {{ item.outcome.shortDescription }} +
    +
    + + check_circle + + folder + chevron_right + {{ template.chipText }} + +
    +
    +
    + +
    +
    +
    + {{ item.outcome.abbreviation }} - {{ item.outcome.shortDescription }} +
    +
    + + check_circle + + folder + chevron_right + {{ template.chipText }} + +
    +
    +
    +
    + +
    + {{ + hoveredTemplate?.type === 'group' ? 'folder' : 'description' + }} +
    +

    + {{ hoveredTemplate?.chipText || 'Select a feedback chip' }} +

    +

    + {{ hoveredTemplate?.description || 'This will populate the comment area with feedback.' }} +

    +
    +
    +
    diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.scss b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.scss new file mode 100644 index 0000000000..7158f04fb8 --- /dev/null +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.scss @@ -0,0 +1,31 @@ +.category-tab-group .mat-mdc-tab-header { + --mdc-secondary-navigation-tab-container-height: 40px; +} + +.template-search .mat-mdc-form-field-subscript-wrapper.mat-mdc-form-field-bottom-align { + height: 0px; +} + +.template-search .mat-mdc-text-field-wrapper, .template-search .mat-mdc-form-field { + height: 40px; +} + +.template-search .mat-mdc-form-field-infix { + min-height: 40px; + padding-top: 5px; + padding-bottom: 5px; +} + +.template-search .mat-mdc-input-element { + font-size: 14px; + padding-top: 3px; +} + +.template-search .material-icons { + font-size: 19px; + padding-top: 5px; +} + +.template-grid .mdc-evolution-chip__graphic.mat-mdc-chip-graphic.ng-star-inserted { + padding-right: 2px; +} diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts new file mode 100644 index 0000000000..696e5ecca9 --- /dev/null +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts @@ -0,0 +1,243 @@ +import { + Component, + ElementRef, + Input, + OnChanges, + Output, + SimpleChanges, + ViewChild, + ViewEncapsulation, + EventEmitter, + OnInit, +} from '@angular/core'; +import {BehaviorSubject, combineLatest, map, Observable} from 'rxjs'; +import { + LearningOutcome, + FeedbackTemplate, + Task, + FeedbackTemplateService, + LearningOutcomeService, + TaskService, +} from 'src/app/api/models/doubtfire-model'; + +@Component({ + selector: 'f-task-feedback-templates', + styleUrl: './task-feedback-templates.component.scss', + templateUrl: './task-feedback-templates.component.html', + encapsulation: ViewEncapsulation.None, +}) +export class TaskFeedbackTemplatesComponent implements OnInit, OnChanges { + @Input() task: Task; + @Output() templateSelected = new EventEmitter(); + + categories = ['TLO', 'ULO', 'GLO']; + selectedTemplates: FeedbackTemplate[] = []; + hoveredTemplate: FeedbackTemplate; + + private generalTemplatesSubject = new BehaviorSubject([]); + generalTemplates$ = this.generalTemplatesSubject.asObservable(); + + private navigationStackSubject = new BehaviorSubject>( + new Map(), + ); + navigationStack$ = this.navigationStackSubject.asObservable(); + + private searchTermSubject = new BehaviorSubject(''); + searchTerm$ = this.searchTermSubject.asObservable(); + + public genTemplates$ = combineLatest([this.generalTemplates$, this.searchTerm$]).pipe( + map(([templates, searchTerm]) => + templates.filter((template) => + template.chipText.toLowerCase().includes(searchTerm.toLowerCase()), + ), + ), + ); + public tlos$: Observable<{outcome: LearningOutcome; templates: FeedbackTemplate[]}[]>; + public ulos$: Observable<{outcome: LearningOutcome; templates: FeedbackTemplate[]}[]>; + public glos$ = combineLatest([ + this.learningOutcomeService.cache.values, + this.feedbackTemplateService.cache.values, + this.navigationStack$, + this.searchTerm$, + ]).pipe( + map(([outcomes, templates, navigationStack, searchTerm]) => + outcomes + .filter((outcome) => outcome.contextType === null) + .map((outcome) => ({ + outcome: outcome, + templates: this.getTemplatesToDisplay(outcome.id, templates, navigationStack, searchTerm), + })) + .filter((glo) => glo.templates.length > 0), + ), + ); + + constructor( + private learningOutcomeService: LearningOutcomeService, + private feedbackTemplateService: FeedbackTemplateService, + private taskService: TaskService, + ) {} + + ngOnInit(): void { + const greetingTemplate = new FeedbackTemplate(); + greetingTemplate.type = 'template'; + greetingTemplate.chipText = 'Greeting'; + greetingTemplate.description = 'Insert a greeting with the student\'s name.'; + + const summaryTemplate = new FeedbackTemplate(); + summaryTemplate.type = 'template'; + summaryTemplate.chipText = 'Summarise feedback'; + summaryTemplate.description = 'Summarise the given feedback.'; + + this.generalTemplatesSubject.next([greetingTemplate, summaryTemplate]); + } + + ngOnChanges(changes: SimpleChanges): void { + this.selectedTemplates = []; + this.navigationStackSubject.next(new Map()); + this.searchTermSubject.next(''); + + if (this.task && this.task.definition) { + this.tlos$ = combineLatest([ + this.task.definition.learningOutcomesCache.values, + this.feedbackTemplateService.cache.values, + this.navigationStack$, + this.searchTerm$, + ]).pipe( + map(([outcomes, templates, navigationStack, searchTerm]) => + outcomes + .map((outcome) => ({ + outcome: outcome, + templates: this.getTemplatesToDisplay( + outcome.id, + templates, + navigationStack, + searchTerm, + ), + })) + .filter((tlo) => tlo.templates.length > 0), + ), + ); + } + + if (this.task.unit) { + this.ulos$ = combineLatest([ + this.task.unit.learningOutcomesCache.values, + this.feedbackTemplateService.cache.values, + this.navigationStack$, + this.searchTerm$, + ]).pipe( + map(([outcomes, templates, navigationStack, searchTerm]) => + outcomes + .map((outcome) => ({ + outcome: outcome, + templates: this.getTemplatesToDisplay( + outcome.id, + templates, + navigationStack, + searchTerm, + ), + })) + .filter((ulo) => ulo.templates.length > 0), + ), + ); + } + } + + private getTemplatesToDisplay( + outcomeId: number, + templates: FeedbackTemplate[], + navigationStack: Map, + searchTerm: string, + ): FeedbackTemplate[] { + const allTemplates = templates.filter((template) => template.learningOutcomeId === outcomeId); + let templatesToDisplay: FeedbackTemplate[] = []; + + if (navigationStack.get(outcomeId) && navigationStack.get(outcomeId).length > 0) { + const outcomeStack = navigationStack.get(outcomeId); + const groupId = outcomeStack[outcomeStack.length - 1]; + + templatesToDisplay.push(allTemplates.find((template) => template.id === groupId)); + allTemplates.forEach((template) => { + if (template.parentChipId === groupId) templatesToDisplay.push(template); + }); + } else { + templatesToDisplay = allTemplates.filter((template) => !template.parentChipId); + } + + templatesToDisplay = templatesToDisplay.filter((template) => + template.chipText.toLowerCase().includes(searchTerm.toLowerCase()), + ); + + return templatesToDisplay; + } + + onSearchTermChange(searchTerm: string): void { + this.searchTermSubject.next(searchTerm); + } + + @ViewChild('tloSection') tloSection!: ElementRef; + @ViewChild('uloSection') uloSection!: ElementRef; + @ViewChild('gloSection') gloSection!: ElementRef; + + scrollToSection(event: any) { + const sections = [this.tloSection, this.uloSection, this.gloSection]; + const selectedSection = sections[event.index]; + + if (selectedSection) { + selectedSection.nativeElement.scrollIntoView({behavior: 'smooth', block: 'start'}); + } + } + + selectTemplate(template: FeedbackTemplate) { + if (template.type === 'template') { + if (template.chipText === 'Greeting') { + template.commentText = `Hi ${this.task.project.student.preferredName}. `; + } else if (template.chipText === 'Summarise feedback') { + if (!this.selectedTemplates || this.selectedTemplates.length < 1) return; + template.commentText = 'Summary of the given feedback:'; + this.selectedTemplates.forEach((t) => { + if (!t.summaryText) return; + template.commentText += '\n- ' + t.summaryText; + }); + } else { + this.selectedTemplates.push(template); + this.suggestTaskStatus(template); + } + this.templateSelected.emit(template); + } else { + const updatedStack = new Map(this.navigationStackSubject.getValue()); + const outcomeStack = updatedStack.get(template.learningOutcomeId) || []; + const index = outcomeStack.indexOf(template.id); + if (index === -1) outcomeStack.push(template.id); + else outcomeStack.splice(index, 1); + updatedStack.set(template.learningOutcomeId, outcomeStack); + this.navigationStackSubject.next(updatedStack); + } + } + + isTemplateSelected(template: FeedbackTemplate): boolean { + return this.selectedTemplates.includes(template); + } + + isGroupExpanded(template: FeedbackTemplate): boolean { + const stack = this.navigationStackSubject.getValue(); + const outcomeStack = stack.get(template.learningOutcomeId) || []; + const index = outcomeStack.indexOf(template.id); + if (index === -1) return false; + else return true; + } + + onHoverTemplate(template: FeedbackTemplate) { + this.hoveredTemplate = template; + } + + private suggestTaskStatus(template: FeedbackTemplate) { + if (template.taskStatus && this.task.suggestedTaskStatus) { + const currentSeq = this.taskService.statusSeq.get(this.task.suggestedTaskStatus); + const templateSeq = this.taskService.statusSeq.get(template.taskStatus); + if (templateSeq < currentSeq) this.task.suggestedTaskStatus = template.taskStatus; + } else { + this.task.suggestedTaskStatus = template.taskStatus; + } + } +} diff --git a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts index 4c53949ae3..5b62675292 100644 --- a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts +++ b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit, Input } from '@angular/core'; -import { TaskComment } from 'src/app/api/models/doubtfire-model'; -import { TaskCommentComposerData } from '../../task-comment-composer/task-comment-composer.component'; +import {Component, OnInit, Input} from '@angular/core'; +import {TaskComment} from 'src/app/api/models/doubtfire-model'; +import {TaskCommentComposerData} from '../../task-comment-composer/task-comment-composer.component'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ selector: 'comment-bubble-action', @@ -11,7 +12,7 @@ export class CommentBubbleActionComponent implements OnInit { @Input() comment: TaskComment; @Input() sharedData: TaskCommentComposerData; - constructor() {} + constructor(private confirmationModalService: ConfirmationModalService) {} ngOnInit() {} reply() { @@ -19,6 +20,12 @@ export class CommentBubbleActionComponent implements OnInit { } delete() { - this.comment.delete(); + this.confirmationModalService.show( + `Delete comment`, + `Are you sure you want to delete this comment?`, + () => { + this.comment.delete(); + }, + ); } } diff --git a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts index c2b6e6761e..37631facda 100644 --- a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core'; -import { commentsModal } from 'src/app/ajs-upgraded-providers'; -import { Project, TaskComment, Task } from 'src/app/api/models/doubtfire-model'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Component, OnInit, Input, Inject, OnDestroy} from '@angular/core'; +import {commentsModal} from 'src/app/ajs-upgraded-providers'; +import {Project, TaskComment, Task} from 'src/app/api/models/doubtfire-model'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {CommentsModalService} from 'src/app/common/modals/comments-modal/comments-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; @Component({ selector: 'pdf-image-comment', @@ -18,7 +19,7 @@ export class PdfImageCommentComponent implements OnInit, OnDestroy { constructor( private alerts: AlertService, - @Inject(commentsModal) private commentsModalRef: any, + @Inject(commentsModal) private commentsModalRef: CommentsModalService, private fileDownloaderService: FileDownloaderService, ) {} @@ -48,7 +49,7 @@ export class PdfImageCommentComponent implements OnInit, OnDestroy { public openCommentsModal() { if (this.resourceUrl) { - this.commentsModalRef.show(this.resourceUrl, this.comment.commentType); + this.commentsModalRef.show(this.resourceUrl, this.comment); } else { this.downloadCommentResource(this.openCommentsModal.bind(this)); } diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html new file mode 100644 index 0000000000..0c44be728c --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -0,0 +1,36 @@ +
    +
    + + @if (!user.isStaff && !task.definition.scormAllowReview) { +
    + } @else { +
    + } + + + + + +
    +
    diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss new file mode 100644 index 0000000000..7bc5f74d91 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss @@ -0,0 +1,47 @@ +p { + color: #2c2c2c; + text-align: center; +} + +hr { + width: 100%; +} + +.hr-fade { + background: linear-gradient(to right, transparent, #9696969d, transparent); + width: 100%; + margin-top: 6px; +} + +.hr-text { + margin: 0; + line-height: 1em; + position: relative; + outline: 0; + border: 0; + color: black; + text-align: center; + height: 1.5em; + opacity: 0.8; + &:before { + content: ""; + background: linear-gradient(to right, transparent, #9696969d, transparent); + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 1px; + } + &:after { + content: attr(data-content); + position: relative; + display: inline-block; + color: black; + + padding: 0 0.5em; + line-height: 1.5em; + + color: #9696969d; + background-color: #fff; + } +} diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts new file mode 100644 index 0000000000..869b79aa51 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -0,0 +1,54 @@ +import {Component, Input, Inject} from '@angular/core'; +import {confirmationModal} from 'src/app/ajs-upgraded-providers'; +import { + Task, + ScormComment, + User, + UserService, + TestAttemptService, +} from 'src/app/api/models/doubtfire-model'; + +@Component({ + selector: 'f-scorm-comment', + templateUrl: './scorm-comment.component.html', + styleUrls: ['./scorm-comment.component.scss'], +}) +export class ScormCommentComponent { + @Input() task: Task; + @Input() comment: ScormComment; + + user: User; + + constructor( + private userService: UserService, + private testAttemptService: TestAttemptService, + @Inject(confirmationModal) private confirmationModal: any, + ) { + this.user = this.userService.currentUser; + } + + reviewScormTest() { + this.comment.testAttempt.review(); + } + + passScormAttempt() { + this.confirmationModal.show( + 'Pass Test Attempt', + 'Are you sure you want to pass this test attempt? This action will override the success status of this test attempt to a pass.', + () => { + this.testAttemptService.overrideSuccessStatus(this.comment.testAttempt.id, true); + }, + ); + } + + deleteScormAttempt() { + this.confirmationModal.show( + 'Delete Test Attempt', + 'Are you sure you want to delete this test attempt? This action is final and will delete information associated with this test attempt.', + () => { + this.testAttemptService.deleteAttempt(this.comment.testAttempt.id); + this.comment.delete(); + }, + ); + } +} diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html new file mode 100644 index 0000000000..b0a74a991e --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html @@ -0,0 +1,29 @@ +
    + @if (comment.assessed) { +
    +
    +

    reason: {{ comment.text }}

    +
    + } + + @if (!comment.assessed) { +
    +
    +

    + {{ message }}
    + reason: {{ comment.text }} +

    + @if (isNotStudent) { + + } +
    +
    + } +
    diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss new file mode 100644 index 0000000000..c2917f902e --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss @@ -0,0 +1,55 @@ +div { + width: 100%; +} + +p { + color: #2c2c2c; + text-align: center; +} + +hr { + width: 100%; +} + +.hr-fade { + background: linear-gradient(to right, transparent, #9696969d, transparent); + width: 100%; +} + +.fade-text { + color: #9696969d; + opacity: 0.8; +} + +.hr-text { + margin: 0; + line-height: 1em; + position: relative; + outline: 0; + border: 0; + color: black; + text-align: center; + height: 1.5em; + opacity: 0.8; + &:before { + content: ""; + background: linear-gradient(to right, transparent, #9696969d, transparent); + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 1px; + } + &:after { + content: attr(data-content); + position: relative; + display: inline-block; + color: black; + + padding: 0 0.5em; + line-height: 1.5em; + + color: #9696969d; + background-color: #fff; + } +} diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts new file mode 100644 index 0000000000..7585e8d7c9 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts @@ -0,0 +1,52 @@ +import {Component, OnInit, Input} from '@angular/core'; +import {ScormExtensionComment, TaskComment, Task} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-scorm-extension-comment', + templateUrl: './scorm-extension-comment.component.html', + styleUrls: ['./scorm-extension-comment.component.scss'], +}) +export class ScormExtensionCommentComponent implements OnInit { + @Input() comment: ScormExtensionComment; + @Input() task: Task; + + constructor(private alerts: AlertService) {} + + private handleError(error: any) { + this.alerts.error('Error: ' + error.data.error, 6000); + } + + ngOnInit() {} + + get message() { + const studentName = this.comment.author.name; + if (this.comment.assessed && this.comment.granted) { + return 'Extra attempt granted.'; + } else if (this.comment.assessed && !this.comment.granted) { + return 'Extra attempt request rejected.'; + } + const subject = this.isStudent ? 'You have ' : studentName + ' has '; + const message = 'requested an extra attempt for the knowledge check.'; + return subject + message; + } + + get isStudent() { + return !this.isNotStudent; + } + + get isNotStudent() { + return this.task.unit.currentUserIsStaff; + } + + grantExtension() { + this.comment.grant().subscribe({ + next: (tc: TaskComment) => { + this.alerts.success('Attempt request granted', 2000); + }, + error: (response) => { + this.handleError(response); + }, + }); + } +} diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html index d30837fce0..4feda189a2 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html @@ -1,16 +1,49 @@ -
    -
    - @if ((comment.assessment_result && comment.assessment_result.is_successful)) { -
    -
    -
    - -
    -
    - } @else { +
    + +
    +
    -
    +
    + @if (comment.overseerStatus === 'pre_queued') { + Tests In Progress + } @else if (comment.overseerStatus === 'passed') { + Tests Passed {{ comment.overseerPassedSteps }} / {{ comment.overseerTotalSteps }} + } @else if (comment.overseerStatus === 'failed') { + Tests Failed {{ comment.overseerPassedSteps }} / {{ comment.overseerTotalSteps }} + } +
    - } +
    + + @if (comment.overseerStatus === 'passed') { + check_circle + } @else if (comment.overseerStatus === 'failed') { + highlight_off_outline + } @else if (comment.overseerStatus === 'pre_queued') { + + } + + @if (comment.overseerStatus !== 'pre_queued') { + + }
    diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss index 816d3724e7..e69de29bb2 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss @@ -1,56 +0,0 @@ -div { - width: 100%; -} - -p { - color: #2c2c2c; - text-align: center; -} - -hr { - width: 100%; -} - -.hr-fade { - background: linear-gradient(to right, transparent, #9696969d, transparent); - width: 100%; - margin-top: 1px; -} - -.fade-text { - color: #9696969d; - opacity: 0.8; -} - -.hr-text { - margin: 0; - line-height: 1em; - position: relative; - outline: 0; - border: 0; - color: black; - text-align: center; - height: 1.5em; - opacity: 0.8; - &:before { - content: ""; - background: linear-gradient(to right, transparent, #9696969d, transparent); - position: absolute; - left: 0; - top: 50%; - width: 100%; - height: 1px; - } - &:after { - content: attr(data-content); - position: relative; - display: inline-block; - color: black; - - padding: 0 0.5em; - line-height: 1.5em; - - color: #9696969d; - background-color: #fff; - } -} diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts index 44e22eea8b..a57f866649 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts @@ -1,8 +1,11 @@ -import { Component, OnInit, Input, Inject } from '@angular/core'; -import { TaskSubmissionService, TaskAssessmentResult } from 'src/app/common/services/task-submission.service'; -import { TaskAssessmentModalService } from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; -import { Task } from 'src/app/api/models/doubtfire-model'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Component, OnInit, Input, Inject} from '@angular/core'; +import { + TaskSubmissionService, + TaskAssessmentResult, +} from 'src/app/common/services/task-submission.service'; +import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; +import {Task} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; export interface User { id: number; @@ -23,6 +26,11 @@ export interface TaskAssessmentComment { recipient_read_time?: Date; // new fields that extend regular Comment Interface. TODO: create a separate Comment entity and extend it. assessment_result?: TaskAssessmentResult; + overseerAssessmentId: number; + overseerPassedSteps: number; + overseerTotalSteps: number; + overseerInProgress: boolean; + overseerStatus: string; } @Component({ @@ -46,19 +54,19 @@ export class TaskAssessmentCommentComponent implements OnInit { } ngOnInit() { - this.update(); + // this.update(); } get message() { return this.comment.assessment_result.assessment_output; } - showTaskAssessmentResult() { - this.modalService.show(this.task); + showTaskAssessmentResult(overseerAssessmentId?: number) { + this.modalService.show(this.task, overseerAssessmentId); } scroll(el: HTMLElement) { - el.scrollIntoView({ behavior: 'smooth' }); + el.scrollIntoView({behavior: 'smooth'}); } update(): void { diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index d104df63af..924ec54829 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -1,5 +1,16 @@ -
    -
    +
    +
    @@ -27,7 +38,7 @@ *ngIf="comment.shouldShowTimestamp" [ngClass]="{own: comment.authorIsMe}" > - {{ comment.author.firstName }} {{ comment.author.lastName }} + {{ comment.author.preferredName }} {{ comment.author.lastName }} {{ comment.createdAt | humanizedDate }}

    -
    +
    +
    +
    + +
    + + + group + + + + {{ comment.text }} + + +
    + +
    + + + comment + + + + {{ comment.text }} + + +
    + +
    + + + how_to_reg + + + + {{ comment.text }} + + +
    + +

    -
    +
    +
    + +
    + -
    +
    + + +
    + +
    diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss index 0ee9fbb91c..5f78a88a4c 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss @@ -140,11 +140,11 @@ $comment-inner-border-radius: 4px; } } - .comment-container .comment-extension { + .comment-container .comment-extension, .comment-container .comment-scorm-extension { width: 100%; } - .comment-container .comment-assessment { + .comment-container .comment-assessment, .comment-container .comment-scorm { width: 100%; } @@ -230,7 +230,7 @@ $comment-inner-border-radius: 4px; overflow-y: hidden; -webkit-box-orient: vertical; -webkit-font-smoothing: antialiased; - overflow-wrap: break-word; + overflow-wrap: anywhere; text-align: left; text-rendering: optimizelegibility; user-select: text; @@ -354,7 +354,7 @@ $comment-inner-border-radius: 4px; } } - .comment .extension-bubble { + .comment .extension-bubble, .comment .scorm_extension-bubble { width: 100%; background-color: transparent; } diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts index 1abfa9934d..d7366dac8d 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts @@ -1,16 +1,36 @@ -import { Component, OnInit, Input, Inject, OnChanges, SimpleChanges, ViewChild, ElementRef } from '@angular/core'; -import { commentsModal } from 'src/app/ajs-upgraded-providers'; -import { Task, Project, TaskComment, TaskCommentService } from 'src/app/api/models/doubtfire-model'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { TaskCommentComposerData } from '../task-comment-composer/task-comment-composer.component'; -import { AlertService } from 'src/app/common/services/alert.service'; +import { + Component, + OnInit, + Input, + Inject, + OnChanges, + SimpleChanges, + ViewChild, + ElementRef, + OnDestroy, +} from '@angular/core'; +import {commentsModal} from 'src/app/ajs-upgraded-providers'; +import { + Task, + Project, + TaskComment, + TaskCommentService, + UserService, + TaskService, +} from 'src/app/api/models/doubtfire-model'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {TaskCommentComposerData} from '../task-comment-composer/task-comment-composer.component'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; +import {CommentsModalService} from 'src/app/common/modals/comments-modal/comments-modal.service'; +import {Subscription} from 'rxjs'; @Component({ selector: 'task-comments-viewer', templateUrl: './task-comments-viewer.component.html', styleUrls: ['./task-comments-viewer.component.scss'], }) -export class TaskCommentsViewerComponent implements OnChanges, OnInit { +export class TaskCommentsViewerComponent implements OnChanges, OnInit, OnDestroy { // Get the comments body from the HTML template @ViewChild('commentsBody') commentsBody: ElementRef; @@ -26,59 +46,128 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { @Input() task: Task; @Input() refocusOnTaskChange: boolean; + private taskStatusSub: Subscription; + private commentAddedSub: Subscription; + constructor( private taskCommentService: TaskCommentService, + private feedbackTemplateService: FeedbackTemplateService, + private userService: UserService, + private taskService: TaskService, private constants: DoubtfireConstants, - @Inject(commentsModal) private commentsModalRef: any, + @Inject(commentsModal) private commentsModalRef: CommentsModalService, private alerts: AlertService, ) { const self = this; - this.taskCommentService.commentAdded$.subscribe((tc: TaskComment) => { + this.commentAddedSub = this.taskCommentService.commentAdded$.subscribe((tc: TaskComment) => { self.scrollDown(); }); + + this.taskStatusSub = this.taskService.taskStatusUpdated$.subscribe((task) => { + if (task && task.project && this.project && task.project.id === this.project.id) { + this.fetchComments(task, false); + } + }); } ngOnInit(): void {} - ngOnChanges(changes: SimpleChanges) { - this.loading = true; + ngOnDestroy(): void { + this.taskStatusSub?.unsubscribe(); + this.commentAddedSub?.unsubscribe(); + } + ngOnChanges(changes: SimpleChanges) { // Must have project for task to be mapped if (changes.task?.currentValue?.project != null) { this.project = changes.task.currentValue.project; - this.taskCommentService - .query( + this.fetchComments(this.task, true, true); + } else { + this.loading = false; + } + } + + fetchComments(task: Task, useCache: boolean = true, fetchAfterCache: boolean = false) { + if (!task.comments.length) { + // If the cache is empty we know the query will attempt to fetch, so we can avoid fetching a second time + useCache = false; + fetchAfterCache = false; + } + + const request$ = !useCache + ? this.taskCommentService.fetchAll({ + projectId: this.project.id, + taskDefinitionId: task.definition.id, + }) + : this.taskCommentService.query( { projectId: this.project.id, - taskDefinitionId: this.task.definition.id, + taskDefinitionId: task.definition.id, }, - this.task, + task, { - cache: this.task.commentCache, - constructorParams: this.task, + cache: task.commentCache, + constructorParams: task, }, - ) - .subscribe((comments) => { - // this.task.comments = comments; + ); - this.task.refreshCommentData(); + request$.subscribe((comments) => { + // Remove task notification + task.numNewComments = 0; - const lastReadComment: TaskComment = this.task.comments - .slice() - .reverse() - .find((comment: TaskComment) => comment.recipientReadTime != null && !comment.recipientIsMe); + for (const comment of comments) { + const existingComment = task.commentCache.get(comment.id); + comment.task = task; + if (!existingComment) { + // Update the cache with any new comments + task.commentCache.add(comment); + } else if ( + existingComment.recipientReadTime !== comment.recipientReadTime || + existingComment.text !== comment.text + ) { + // Update cached read receipts or edited messages + task.commentCache.set(comment.id, comment); + } + } + + for (const cachedComment of task.comments) { + if (!comments.find((c) => c.id === cachedComment.id)) { + // This comment is in cache but not in the latest comments list + task.commentCache.delete(cachedComment.id); + } + } + + task.refreshCommentData(); - setTimeout(() => { - this.loading = false; - this.scrollDown(); - }, 1000); + const lastReadComment: TaskComment = task.comments + .slice() + .reverse() + .find( + (comment: TaskComment) => comment.recipientReadTime != null && !comment.recipientIsMe, + ); - if (lastReadComment) { - lastReadComment.lastRead = true; - } + setTimeout(() => { + this.loading = false; + this.scrollDown(); + if (useCache && fetchAfterCache) { + this.fetchComments(task, false, false); + } + }, 100); + + if (lastReadComment) { + for (const comment of task.comments) { + comment.lastRead = false; + } + lastReadComment.lastRead = true; + } + }); + + if (this.project.unit.currentUserIsStaff) { + this.feedbackTemplateService + .query({contextType: 'task_definitions', contextId: task.definition.id}, {}) + .subscribe({ + error: () => this.alerts.error('Error loading task feedback templates.'), }); - } else { - this.loading = false; } } @@ -98,6 +187,10 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { return this.constants.IsOverseerEnabled.value; } + get scormEnabled(): boolean { + return this.task.scormEnabled; + } + uploadFiles(event) { [...event].forEach((file) => { if ( @@ -146,11 +239,19 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { openCommentsModal(comment: TaskComment) { const resourceUrl = comment.attachmentUrl; - this.commentsModalRef.show(resourceUrl, comment.commentType); + this.commentsModalRef.show(resourceUrl, comment); } shouldShowAuthorIcon(commentType: string) { - return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment'); + return !( + commentType === 'extension' || + commentType === 'status' || + commentType == 'assessment' || + commentType === 'scorm' || + commentType === 'scorm_extension' || + commentType === 'discussed_in_class' || + commentType === 'checked_in' + ); } commentClasses(comment: TaskComment): object { diff --git a/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee b/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee index 51633d4fb6..b40980c706 100644 --- a/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee +++ b/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.tasks.task-ilo-alignment.modals.task-ilo-alignment-modal', []) # diff --git a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee index b8aad86bb6..8381daf763 100644 --- a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee +++ b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.tasks.task-ilo-alignment.task-ilo-alignment-editor',[]) .directive('taskIloAlignmentEditor', -> diff --git a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee index 0dfeb7598c..9179c4c6bd 100644 --- a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee +++ b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.tasks.task-ilo-alignment.task-ilo-alignment-rater',[]) # diff --git a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee index 2980696c1c..e95cbfdc5d 100644 --- a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee +++ b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.tasks.task-ilo-alignment.task-ilo-alignment-viewer', []) # diff --git a/src/app/tasks/task-submission-history/task-submission-history.component.html b/src/app/tasks/task-submission-history/task-submission-history.component.html index 4f261b27bd..c561635816 100644 --- a/src/app/tasks/task-submission-history/task-submission-history.component.html +++ b/src/app/tasks/task-submission-history/task-submission-history.component.html @@ -1,27 +1,42 @@ -
    -
    -
    -
    Submissions
    - +
    +
    +
    +
    Submissions
    + @for (tab of tabs; track tab) { - -
    {{tab.timestamp | date: 'dd/MM/yy, hh:mm a'}}
    -   -
    -} + +
    +
    + {{ tab.timestamp | humanizedDate }} +
    + @if (tab.status === 'pre_queued') { + schedule + } @else { + + } +
    +
    + }
    -
    +
    @for (selTab of selectedTab.content; track selTab) { - -
    {{selTab.result}} 
    - -
    -} + +
    {{ selTab.result }} 
    + +
    + }
    diff --git a/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee b/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee index 084f2cc69e..1aef6ca1b3 100644 --- a/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee +++ b/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.units.modals.unit-ilo-edit-modal', []) # # Modal to edit or create a new ILO diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html new file mode 100644 index 0000000000..dbd2f4302a --- /dev/null +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -0,0 +1,114 @@ + + + +

    Tutor Times Session Summary

    +
    + +
    + @if (role === 'Convenor') { + + } + + +
    +
    + +
    +
    + + + +
    +
    + + Choose a date + + Sessions from this day onward + + + + + + Choose a date + + Sessions up to this day + + + +
    +
    + Hide sessions during tutorials +
    +
    + + +
    + {{ event.tutorName }} ({{ event.duration }} minutes) + {{ event.duringTutorial ? 'T' : '' }}
    + {{ event.startHour }} — {{ event.endHour }}
    + Assessments: {{ event.assessments || 0 }}
    + Comments: {{ event.commentsAdded || 0 }}
    + Submissions opened: {{ event.submissionsOpened || 0 }}
    + During Tutorial?: {{ event.duringTutorial ? 'yes' : 'no' }} +
    +
    + +
    + @if (isLoading) { + + + } + + +
    +
    diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss new file mode 100644 index 0000000000..2ce45fc98d --- /dev/null +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss @@ -0,0 +1,16 @@ +.cal-week-view { + position: relative; + max-height: 750px; + overflow-y: scroll; + overscroll-behavior: contain; +} + +.cal-day-headers { + position: sticky; + top: 0; + right: 0; + z-index: 2; + background-color: white; + width: 100%; + min-height: 35px; +} diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts new file mode 100644 index 0000000000..a3451a78de --- /dev/null +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -0,0 +1,306 @@ +import {Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; +import {MatDatepickerInputEvent} from '@angular/material/datepicker'; +import {Observable} from 'rxjs'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {Unit} from 'src/app/api/models/unit'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +interface SessionEvent { + start: Date; + end: Date; + startHour: string; + endHour: string; + title: string; + color: { + primary: string; + secondary: string; + }; + userId: number; + commentsAdded: number; + assessments: number; + submissionsOpened: number; + duration: number; + duringTutorial: boolean; + tutorName: string; +} + +@Component({ + selector: 'f-analytics-tutor-times', + templateUrl: 'analytics-tutor-times.component.html', + styleUrls: ['analytics-tutor-times.component.scss'], + encapsulation: ViewEncapsulation.None, +}) +export class AnalyticsTutorTimesComponent implements OnInit { + @Input() unit: Unit; + + @Input() downloadCsvFn!: ( + newJob: Observable, + title: string, + filename: string, + ) => void; + + selectedUserId: number | null = null; + + viewDate = new Date(); + events: SessionEvent[] = []; + filteredEvents = []; + + tutorTimeSummaryStartDate: Date; + tutorTimeSummaryEndDate: Date; + daysInWeek: number = 7; + + hideSessionsDuringTutorials: boolean = false; + + public canLoadSessions: boolean = false; + public isLoading: boolean = false; + + constructor( + private alertService: AlertService, + private sidekiqProgressModalService: SidekiqProgressModalService, + private fileDownloaderService: FileDownloaderService, + private userService: UserService, + ) {} + + get role() { + return this.unit.staff.find((s) => s.user.id === this.userService.currentUser.id)?.role; + } + + ngOnInit(): void { + if (!this.sidekiqProgressModalService || !this.fileDownloaderService) { + // NOTE: Our `downloadCsvFn` callback requires these services because it calls `this` context + console.error('Failed to load tutor times analytics'); + } + + this.tutorTimeSummaryEndDate = new Date(); + this.tutorTimeSummaryEndDate.setHours(0, 0, 0, 0); + + this.tutorTimeSummaryStartDate = new Date(this.tutorTimeSummaryEndDate); + this.tutorTimeSummaryStartDate.setDate(this.tutorTimeSummaryEndDate.getDate() - 7); + + const startOfWeek = new Date(this.viewDate); + startOfWeek.setDate(this.viewDate.getDate() - this.daysInWeek + 1); + + this.viewDate = startOfWeek; + + this.canLoadSessions = true; + this.getMarkingSesssions(); + } + + goPreviousWeek() { + this.canLoadSessions = true; + this.viewDate = new Date(this.viewDate.getTime() - this.daysInWeek * 24 * 60 * 60 * 1000); + } + + goNextWeek() { + this.canLoadSessions = true; + this.viewDate = new Date(this.viewDate.getTime() + this.daysInWeek * 24 * 60 * 60 * 1000); + } + + goTodayWeek() { + this.canLoadSessions = true; + + this.tutorTimeSummaryEndDate = new Date(); + this.tutorTimeSummaryStartDate = new Date( + this.tutorTimeSummaryEndDate.getTime() - 7 * 24 * 60 * 60 * 1000, + ); + this.daysInWeek = 7; + + this.viewDate = new Date(); + const startOfWeek = new Date(); + startOfWeek.setDate(this.viewDate.getDate() - this.daysInWeek + 1); + + this.viewDate = startOfWeek; + } + + public onToggleChangeHideSessionsDuringTutorial() { + setTimeout(() => { + this.applyFilters(); + }); + } + + applyFilters() { + this.filteredEvents = this.events.filter( + (e) => + (this.selectedUserId === null || e.userId === this.selectedUserId) && + (!this.hideSessionsDuringTutorials || !e.duringTutorial) && + e.duration >= 1, + ); + } + + onDateChange(_event: MatDatepickerInputEvent) { + if (!this.tutorTimeSummaryStartDate || !this.tutorTimeSummaryEndDate) { + return; + } + + // Includes both the selected start & end days + const diffDays = + Math.floor( + (this.tutorTimeSummaryEndDate.getTime() - this.tutorTimeSummaryStartDate.getTime()) / + (1000 * 60 * 60 * 24), + ) + 1; + + if (diffDays > 366) { + this.alertService.error('You cannot select more than a year', 3000); + return; + } + if (diffDays < 1) { + this.tutorTimeSummaryStartDate = this.tutorTimeSummaryEndDate; + this.alertService.error('End date must be on or after the start date'); + return; + } + this.canLoadSessions = true; + this.daysInWeek = diffDays; + this.viewDate = new Date(this.tutorTimeSummaryStartDate); + } + + beforeViewRender(event): void { + console.log(event.period.start); + console.log(event.period.end); + + this.tutorTimeSummaryStartDate = event.period.start; + this.tutorTimeSummaryEndDate = event.period.end; + + this.getMarkingSesssions(); + } + + public getTutorTimesSummary() { + const start = `${this.tutorTimeSummaryStartDate.getFullYear()}-${(this.tutorTimeSummaryStartDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryStartDate.getDate().toString().padStart(2, '0')}`; + const end = `${this.tutorTimeSummaryEndDate.getFullYear()}-${(this.tutorTimeSummaryEndDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryEndDate.getDate().toString().padStart(2, '0')}`; + + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + + this.downloadCsvFn( + this.unit.downloadTutorTimesSummaryCsv( + this.tutorTimeSummaryStartDate, + this.tutorTimeSummaryEndDate, + tz, + this.hideSessionsDuringTutorials, + ), + 'Tutor Times Summary CSV', + `${this.unit.code}-tutor-times-summary-${start}-to-${end}-${tz}-${!this.hideSessionsDuringTutorials ? 'incl-tutorials' : ''}.csv`, + ); + } + + public getMyTutorTimesSessions() { + const start = `${this.tutorTimeSummaryStartDate.getFullYear()}-${(this.tutorTimeSummaryStartDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryStartDate.getDate().toString().padStart(2, '0')}`; + const end = `${this.tutorTimeSummaryEndDate.getFullYear()}-${(this.tutorTimeSummaryEndDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryEndDate.getDate().toString().padStart(2, '0')}`; + + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + + this.downloadCsvFn( + this.unit.downloadMyTutorTimeSessionsCsv( + this.tutorTimeSummaryStartDate, + this.tutorTimeSummaryEndDate, + tz, + ), + 'My Marking Sessions CSV', + `${this.unit.code}-${this.userService.currentUser.name}-sessions-${start}-to-${end}-${tz}.csv`, + ); + } + + public getMarkingSesssions() { + if (!this.canLoadSessions) { + return; + } + + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + + this.canLoadSessions = false; + this.isLoading = true; + this.unit + .getUserMarkingSessions(this.tutorTimeSummaryStartDate, this.tutorTimeSummaryEndDate, tz) + .subscribe({ + next: (data) => { + this.isLoading = false; + this.canLoadSessions = false; + this.events = data.map((session) => { + const tutor = this.unit.staff.find((t) => t.user.id === session.user?.id); + + const primary = tutor ? this.stringToHexColor(tutor.user.firstName) : '#e0e0e0'; + const secondary = tutor ? this.stringToHexColor(tutor.user.firstName) : '#e3e2e1'; + return { + start: new Date(session.startTime), + end: new Date(session.endTime), + startHour: new Date(session.startTime).toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }), + endHour: new Date(session.endTime).toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }), + title: `${tutor?.user?.firstName ?? 'N/A'} (${session.durationMinutes}m) ${session.duringTutorial ? '(T)' : ''}`, + color: {primary: secondary, secondary: primary}, + userId: session.user?.id, + commentsAdded: session.commentsAdded, + assessments: session.assessments, + submissionsOpened: session.submissionsOpened, + duration: session.durationMinutes, + duringTutorial: session.duringTutorial, + tutorName: tutor?.user?.firstName ?? 'N/A', + }; + }); + + this.applyFilters(); + }, + error: (error) => { + this.canLoadSessions = false; + this.alertService.error(`Failed to load sessions: ${error}`, 6000); + console.error(error); + }, + }); + } + + eventClicked({event}: {event: SessionEvent}): void { + if (event.userId !== undefined) { + if (this.selectedUserId === null) { + this.selectedUserId = Number(event.userId); + } else { + this.selectedUserId = null; + } + this.applyFilters(); + } + } + + private stringToHexColor( + name: string, + opts?: {hue?: [number, number]; sat?: [number, number]; lit?: [number, number]}, + ): string { + const options = { + hue: opts?.hue || [0, 360], + sat: opts?.sat || [40, 70], // lower saturation → softer color + lit: opts?.lit || [75, 90], // higher lightness → pastel tone + }; + + const range = (hash: number, min: number, max: number) => { + const diff = max - min; + const x = ((hash % diff) + diff) % diff; + return x + min; + }; + + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = name.charCodeAt(i) + ((hash << 5) - hash); + hash = hash & hash; + } + + const h = range(hash, options.hue[0], options.hue[1]); + const s = range(hash, options.sat[0], options.sat[1]) / 100; + const l = range(hash, options.lit[0], options.lit[1]) / 100; + + const a = s * Math.min(l, 1 - l); + const f = (n: number) => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); + return Math.round(255 * color); + }; + + const toHex = (c: number) => c.toString(16).padStart(2, '0'); + return `#${toHex(f(0))}${toHex(f(8))}${toHex(f(4))}`; + } +} diff --git a/src/app/units/states/analytics/unit-analytics-route.component.html b/src/app/units/states/analytics/unit-analytics-route.component.html index 643d344195..40017c59e7 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.html +++ b/src/app/units/states/analytics/unit-analytics-route.component.html @@ -1,4 +1,22 @@

    Unit Statistics

    - - +
    + + + + + + + + + + +
    diff --git a/src/app/units/states/analytics/unit-analytics-route.component.ts b/src/app/units/states/analytics/unit-analytics-route.component.ts index 3029bcdd6a..4c8e068722 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.ts +++ b/src/app/units/states/analytics/unit-analytics-route.component.ts @@ -1,5 +1,13 @@ -import { Component, Input } from '@angular/core'; -import { Unit } from 'src/app/api/models/unit'; +import {Component, Input, OnInit} from '@angular/core'; +import {MatDatepickerInputEvent} from '@angular/material/datepicker'; +import {CalendarEvent} from 'angular-calendar'; +import {Observable} from 'rxjs'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {Unit} from 'src/app/api/models/unit'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; @Component({ selector: 'f-unit-analytics', @@ -8,4 +16,67 @@ import { Unit } from 'src/app/api/models/unit'; }) export class UnitAnalyticsComponent { @Input() unit: Unit; + + constructor( + private sidekiqProgressModalService: SidekiqProgressModalService, + private alertsService: AlertService, + private fileDownloaderService: FileDownloaderService, + private userService: UserService, + private alertService: AlertService, + ) {} + + get role() { + return this.unit.staff.find((s) => s.user.id === this.userService.currentUser.id)?.role; + } + + public getTaskCompletionCsv() { + this.downloadCsv( + this.unit.downloadTaskCompletionCsv(), + 'Task Completion Stats CSV', + `${this.unit.code}-task-completion-stats.csv`, + ); + } + + public getTutorAssessmentCsv() { + this.downloadCsv( + this.unit.downloadTutorAssessmentCsv(), + 'Tutor Assessment Stats CSV', + `${this.unit.code}-tutor-assessment-stats.csv`, + ); + } + + public getTasksAwaitingFeedbackCsv() { + this.downloadCsv( + this.unit.downloadTasksAwaitingFeedbackCsv(), + 'Tasks Awaiting Feedback CSV', + `${this.unit.code}-tasks-awaiting-feedback.csv`, + ); + } + + public getTaskAssessmentCountCsv() { + this.downloadCsv( + this.unit.downloadTaskAssessmentCountsCsv(), + 'Task Assessment Counts CSV', + `${this.unit.code}-task-assessment-counts.csv`, + ); + } + + public downloadCsv(newJob: Observable, title: string, filename: string) { + newJob.subscribe({ + next: (job) => { + if (!job || !job.id) { + return this.alertsService.error(`Failed to download ${title}`, 6000); + } + this.sidekiqProgressModalService.show(`Downloading ${title}`, job.id).subscribe((job) => { + const blob = new Blob([job.result], {type: 'text/csv'}); + const url = URL.createObjectURL(blob); + + this.fileDownloaderService.downloadBlobToFile(url, filename); + }); + }, + error: (_error) => { + this.alertsService.error(`Could not download ${title}`, 6000); + }, + }); + } } diff --git a/src/app/units/states/edit/directives/directives.coffee b/src/app/units/states/edit/directives/directives.coffee index bfb12ed317..4da41cacfb 100644 --- a/src/app/units/states/edit/directives/directives.coffee +++ b/src/app/units/states/edit/directives/directives.coffee @@ -1,6 +1,4 @@ angular.module('doubtfire.units.states.edit.directives', [ - 'doubtfire.units.states.edit.directives.unit-details-editor' 'doubtfire.units.states.edit.directives.unit-group-set-editor' 'doubtfire.units.states.edit.directives.unit-ilo-editor' - 'doubtfire.units.states.edit.directives.unit-staff-editor' ]) diff --git a/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.html b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.html new file mode 100644 index 0000000000..10618f6bc8 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.html @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.scss b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.scss new file mode 100644 index 0000000000..a4e1d77cc6 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.scss @@ -0,0 +1,3 @@ +mat-form-field { + padding: 1rem; +} diff --git a/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts new file mode 100644 index 0000000000..f7524cce33 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts @@ -0,0 +1,123 @@ +// +// Modal to show Doubtfire version info +// +import {Injectable, Component, Inject, AfterViewInit, OnInit} from '@angular/core'; + +import {MatDialog, MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Observable} from 'rxjs'; +import {D2lAssessmentMapping} from 'src/app/api/models/d2l/d2l_assessment_mapping'; +import {D2lAssessmentMappingService} from 'src/app/api/models/doubtfire-model'; +import {Unit} from 'src/app/api/models/unit'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-d2l-unit-details-form', + templateUrl: 'd2l-unit-details-form.component.html', + styleUrl: 'd2l-unit-details-form.component.scss', +}) +export class D2lUnitDetailsFormComponent implements OnInit { + public d2lDataMapping: D2lAssessmentMapping = new D2lAssessmentMapping(this.data); + + constructor( + @Inject(MAT_DIALOG_DATA) public data: Unit, + @Inject(MatDialogRef) + public dialogRef: MatDialogRef, + private alertService: AlertService, + public d2lAssessmentMappingService: D2lAssessmentMappingService, + ) {} + + ngOnInit(): void { + this.data.loadD2lMapping().subscribe({ + next: (d2lDataMapping) => { + this.d2lDataMapping = d2lDataMapping; + }, + error: (_err) => { + // No mapping found, create a new one + this.d2lDataMapping = new D2lAssessmentMapping(this.data); + }, + }); + } + + private saveAction(): Observable { + if (!this.d2lDataMapping.id) { + if (!this.d2lDataMapping.orgUnitId && !this.d2lDataMapping.gradeObjectId) { + return null; + } + return this.d2lAssessmentMappingService.post( + { + unitId: this.data.id, + id: undefined, + }, + { + entity: this.d2lDataMapping, + constructorParams: this.data, + }, + ); + } else if (this.d2lDataMapping.hasChanges(this.d2lAssessmentMappingService.mapping)) { + return this.d2lAssessmentMappingService.update( + { + unitId: this.data.id, + id: this.d2lDataMapping.id, + }, + { + entity: this.d2lDataMapping, + }, + ); + } else { + return null; + } + } + + public saveAndClose(): void { + const action = this.saveAction(); + + if (action) { + action.subscribe({ + next: () => { + this.alertService.success('D2l details saved successfully'); + // Close the dialog + this.dialogRef.close(); + }, + error: (err) => { + this.alertService.error(`Failed to save unit ${err}`); + console.error(err); + }, + }); + } else { + this.dialogRef.close(); + } + } + + public delete(): void { + this.d2lAssessmentMappingService + .delete({unitId: this.data.id, id: this.d2lDataMapping.id}) + .subscribe({ + next: () => { + this.alertService.success('D2l details deleted successfully'); + this.data.d2lMapping = undefined; + this.dialogRef.close(); + }, + error: (err) => { + this.alertService.error(`Failed to delete D2L details: ${err}`); + console.error(err); + }, + }); + } +} + +/** + * The about doubtfire modal service - used to create and show the modal + */ +// eslint-disable-next-line max-classes-per-file +@Injectable() +export class D2lUnitDetailsModal { + constructor(public dialog: MatDialog) {} + + public open(unit: Unit): void { + // Show dialog while the data above is being fetched + this.dialog.open(D2lUnitDetailsFormComponent, { + width: '600px', + data: unit, + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee deleted file mode 100644 index c1fe9e38fa..0000000000 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee +++ /dev/null @@ -1,84 +0,0 @@ -angular.module('doubtfire.units.states.edit.directives.unit-details-editor', []) - -# -# Editor for the basic details of a unit, such as the name, code -# start and end dates etc. -# -.directive('unitDetailsEditor', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html' - controller: ($scope, $state, $rootScope, DoubtfireConstants, newUnitService, alertService, newTeachingPeriodService, TaskSubmission) -> - $scope.overseerEnabled = DoubtfireConstants.IsOverseerEnabled - - $scope.calOptions = { - startOpened: false - endOpened: false - portfolioAutoGenerationOpened: false - } - - # Get docker images available for automated task assessment for the unit. - TaskSubmission.getDockerImagesAsPromise().then (images) -> - $scope.dockerImages = images - - # Get the confugurable, external name of Doubtfire - $scope.externalName = DoubtfireConstants.ExternalName - - # get the teaching periods- gets an object with the loaded teaching periods - newTeachingPeriodService.query().subscribe((periods) -> - $scope.teachingPeriods = periods - $scope.teachingPeriodValues = [{value: undefined, text: "None"}] - other = _.map periods, (p) -> {value: p, text: "#{p.year} #{p.period}"} - _.each other, (d) -> $scope.teachingPeriodValues.push(d) - ) - - $scope.teachingPeriodSelected = ($event) -> - $scope.unit.teachingPeriod = $event - - $scope.unit.taskDefinitionCache.values.subscribe( - (taskDefs) -> - $scope.taskDefinitionValues = [{value: undefined, text: "None"}] - other = _.map taskDefs, (td) -> {value: td, text: "#{td.abbreviation}-#{td.name}"} - _.each other, (d) -> $scope.taskDefinitionValues.push(d) - ) - - $scope.draftTaskDefSelected = ($event) -> - $scope.unit.draftTaskDefinition = $event - - # Datepicker opener - $scope.open = ($event, pickerData) -> - $event.preventDefault() - $event.stopPropagation() - - if pickerData == 'start' - $scope.calOptions.startOpened = ! $scope.calOptions.startOpened - $scope.calOptions.endOpened = false - $scope.calOptions.portfolioAutoGenerationOpened = false - else if pickerData == 'end' - $scope.calOptions.startOpened = false - $scope.calOptions.endOpened = ! $scope.calOptions.endOpened - $scope.calOptions.portfolioAutoGenerationOpened = false - else if pickerData == 'autogen' - $scope.calOptions.startOpened = false - $scope.calOptions.endOpened = false - $scope.calOptions.portfolioAutoGenerationOpened = ! $scope.calOptions.portfolioAutoGenerationOpened - - $scope.dateOptions = { - formatYear: 'yy', - startingDay: 1 - } - $scope.studentSearch = "" - - $scope.saveUnit = -> - newUnitService.update($scope.unit).subscribe({ - next: (unit) -> - alertService.success( "Unit updated.", 2000) - error: (response) -> - alertService.error( "Failed to update unit. #{response}", 6000) - }) - -) - - - - diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html new file mode 100644 index 0000000000..073c69ce2a --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html @@ -0,0 +1,243 @@ +
    +
    +

    Unit Details

    +

    Edit and configure all details and settings for this unit.

    +
    + + + Code + + + + + Name + + + + + Description + + + + + + + Teaching Period + + None + @for (period of teachingPeriods; track period) { + {{ period.name }} + } + + + +
    + @if (!unit.teachingPeriod) { + + Start Date + + + + + + End Date + + + + + } @else { + + {{ unit.teachingPeriod.name }} Start Date + + + + {{ unit.teachingPeriod.name }} End Date + + + } +
    + + + Portfolio Auto-Generation Date + + + + + + + Draft Learning Summary + + None + @for (td of taskDefinitions; track td) { + {{ td.abbreviation }} - {{ td.name }} + } + + + When a draft learning summary task is selected, this will ensure a students uploaded draft + is automatically added to the students portfolio. + + + + + Extension duration onresubmit + + + When tutors request resubmission of a task, this setting determines how many weeks the task + will be extended to allow students to fix and resubmit their work. + + + +
    + + Feedback warning after (days) + + + Tasks in inbox are highlighted if feedback isn’t given within this many days of + submission. + + + + + Show task in overflow queue after (days) + + + Tasks without feedback for this many days will appear in the overflow queue. + + +
    +
    + + +
    + Allow flexible dates +

    Allows students to set planned due dates, without using extensions.

    +
    + +
    + Allow student extensions +

    When false only staff can request extensions on behalf of students.

    +
    + +
    + Auto apply extensions +

    + When true, extensions will be automatically applied when they result in a date that is + between the task's due date and deadline. +

    +
    + +
    + Has tasks assessed in portfolio +

    + When enabled, late submissions will not be automatically marked as "Time Exceeded" or + "Feedback Exceeded", and will instead appear as "Assess in Portfolio". Tutors can still sign + off tasks as complete unless the task definition has the "Assess in Portfolio Only" option + enabled. +

    +
    + +
    + Allow students to change tutorial +

    When false only staff can change student tutorials.

    +
    + +
    + Send notification emails +

    + When true, emails will be set to students each week to indicate progress and suggest future + tasks for them to work on. +

    +
    + +
    + Synchronise enrolments +

    + When true student enrolments will be synchronised with other systems where this is possible. +

    +
    + +
    + Synchronise timetable +

    + When true timetable data will be synchronised with other systems where this is possible. +

    +
    + +
    + Active +

    Set to false to hide unit from students and tutors.

    +
    +
    + + @if (overseerEnabled.value) { + +
    + Overseer assessment +

    If true, unit tasks will be able to make use of Overseer automated checking.

    +
    + + + Overseer Docker Image + + @for (image of dockerImages; track image) { + {{ image.description }} + } + + Use this to select the default container used to check tasks with Overseer. + +
    + } + +
    + + + +
    +
    diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.scss b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts new file mode 100644 index 0000000000..7ac7161a73 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts @@ -0,0 +1,109 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {MatSlideToggleChange} from '@angular/material/slide-toggle'; +import {OverseerImage, UnitService} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TeachingPeriod} from 'src/app/api/models/teaching-period'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {D2lUnitDetailsModal} from './d2l-details-form/d2l-unit-details-form.component'; + +@Component({ + selector: 'f-unit-details-editor', + templateUrl: 'unit-details-editor.component.html', + styleUrls: ['unit-details-editor.component.scss'], +}) +export class UnitDetailsEditorComponent implements OnInit { + @Input() unit: Unit; + + constructor( + private teachingPeriodService: TeachingPeriodService, + private taskDefinitionService: TaskDefinitionService, + private doubtfireConstants: DoubtfireConstants, + private taskSubmissionService: TaskSubmissionService, + private d2lUnitDetailsModal: D2lUnitDetailsModal, + private unitService: UnitService, + private alertsService: AlertService, + private confirmationModal: ConfirmationModalService, + ) {} + + public teachingPeriods: TeachingPeriod[]; + public taskDefinitions: TaskDefinition[]; + public dockerImages: OverseerImage[]; + + public get overseerEnabled() { + return this.doubtfireConstants.IsOverseerEnabled; + } + + public get d2lEnabled() { + return this.doubtfireConstants.IsD2LEnabled; + } + + ngOnInit(): void { + this.teachingPeriodService.query().subscribe((periods) => { + this.teachingPeriods = periods; + }); + + this.unit.taskDefinitionCache.values.subscribe((taskDefs) => { + this.taskDefinitions = taskDefs; + }); + + this.taskSubmissionService.getDockerImagesAsPromise().then((images) => { + this.dockerImages = images; + }); + } + + addD2lData() { + this.d2lUnitDetailsModal.open(this.unit); + } + + saveUnit() { + this.unitService.update(this.unit).subscribe({ + next: (_unit) => { + this.alertsService.success('Unit updated.', 2000); + }, + error: (response) => { + this.alertsService.error(`Failed to update unit. ${response}`, 6000); + }, + }); + } + + private updatingAssessInPortfolio: boolean = false; + + onToggleAssessInPortfolio(event: MatSlideToggleChange) { + if (!event.checked || this.updatingAssessInPortfolio) { + return false; + } + + if (this.updatingAssessInPortfolio) { + return; + } + + this.updatingAssessInPortfolio = true; + + setTimeout(() => { + this.unit.markLateSubmissionsAsAssessInPortfolio = false; + const modal = this.confirmationModal.show( + 'Enable Assess in Portfolio?', + `Are you sure you want to enable "Assess in Portfolio" for late submissions? + This will update any existing Time Exceeded tasks to the "Assess in Portfolio" state. + You will not be able to disable this setting while any tasks remain in the "Assess in Portfolio" state.`, + () => { + this.unit.markLateSubmissionsAsAssessInPortfolio = true; + setTimeout(() => { + this.updatingAssessInPortfolio = false; + }); + }, + ); + modal.afterClosed().subscribe(() => { + setTimeout(() => { + this.updatingAssessInPortfolio = false; + }); + }); + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html deleted file mode 100644 index 3cd81f09c4..0000000000 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html +++ /dev/null @@ -1,432 +0,0 @@ -
    -
    -
    -

    Create Unit

    - Create a new unit with all overview unit details here. -
    -
    -

    Update Unit

    - Update overview details of the unit below. -
    -
    -
    -
    - -
    - -
    -
    - - -
    - -
    - -
    -
    - - -
    - -
    - -
    -
    - - -
    - -
    - -
    -
    - - -
    - -
    - - - - When a draft learning summary task is selected, this will ensure a students uploaded draft is - automatically added to the students portfolio. - -
    -
    - - -
    - -
    -
    - - - - - -
    -
    -
    - - -
    - -
    -
    - - - - - -
    -
    -
    - - -
    - -
    -
    - - - - -
    -
    -
    - - -
    - -
    -
    - - -
    - When false only staff can request extensions on behalf of students. -
    -
    - - -
    - -
    - - - When tutors request resubmission of a task, this setting determines how many weeks the task will be - extended to allow students to fix and resubmit their work. - -
    -
    - - -
    - -
    -
    - - -
    - - When true, extensions will be automatically applied when they result in a date that is between the task's - due date and deadline. - -
    -
    - - -
    - -
    -
    - - -
    - When false only staff can change student tutorials. -
    -
    - - -
    - -
    -
    - - -
    - - When true, emails will be set to students each week to indicate progress and suggest future tasks for them - to work on. - -
    -
    - - -
    - -
    -
    - - -
    - - When true student enrolments will be synchronised with other systems where this is possible. - -
    -
    - - -
    - -
    -
    - - -
    - - When true timetable data will be synchronised with other systems where this is possible. - -
    -
    - - -
    - -
    -
    - - -
    - - If true, unit tasks will be able to make use of Overseer automated checking. - -
    -
    - -
    - -
    - -
    - -
    -
    diff --git a/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee b/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee index 54209881ac..151d331a77 100644 --- a/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee +++ b/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee @@ -1,3 +1,5 @@ +# Component not used + angular.module('doubtfire.units.states.edit.directives.unit-ilo-editor',[]) # diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee deleted file mode 100644 index 3856daefe5..0000000000 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee +++ /dev/null @@ -1,58 +0,0 @@ -angular.module('doubtfire.units.states.edit.directives.unit-staff-editor', []) - -# -# Editor for adding new staff to a unit and assigning those staff -# members new unit roles within the unit -# -.directive('unitStaffEditor', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html' - controller: ($scope, $rootScope, alertService, newUnitService, newUnitRoleService) -> - temp = [] - users = [] - - $scope.unit.staffCache.values.subscribe( (staff) -> $scope.unitStaff = staff ) - - $scope.changeRole = (unitRole, role_id) -> - unitRole.roleId = role_id - newUnitRoleService.update(unitRole).subscribe({ - next: (response) -> alertService.success( "Role changed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.changeMainConvenor = (staff) -> - $scope.unit.changeMainConvenor(staff).subscribe({ - next: (response) -> - alertService.success( "Main convenor changed", 2000) - error: (response) -> - alertService.error( response, 6000) - }) - - $scope.addSelectedStaff = -> - staff = $scope.selectedStaff - $scope.selectedStaff = null - $scope.unit.staff = [] unless $scope.unit.staff - - if staff.id? - $scope.unit.addStaff(staff).subscribe({ - next: (response) -> alertService.success( "Staff member added", 2000) - error: (response) -> alertService.error( response, 6000) - }) - else - alertService.error( "Unable to add staff member. Ensure they have a tutor or convenor account in User admin first.", 6000) - - # Used in the typeahead to filter staff already in unit - $scope.filterStaff = (staff) -> - not _.find($scope.unit.staff, (listStaff) -> staff.id == listStaff.user.id) - - $scope.removeStaff = (staff) -> - newUnitRoleService.delete(staff, {cache: $scope.unit.staffCache}).subscribe({ - next: (response) -> alertService.success( "Staff member removed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.groupSetName = (id) -> - $scope.unit.groupSetsCache.get(id)?.name || "Individual Work" - -) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html new file mode 100644 index 0000000000..c95e5c847e --- /dev/null +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -0,0 +1,139 @@ +
    +
    +

    Unit Staff

    +

    Manage unit staff by adding members and assigning them as convenors or tutors.

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name +
    + {{ unitRole.user.name }} +
    +
    Role + + Tutor + Convenor + + Main Convenor + @if (unitRole?.role === 'Convenor') { + + } + Observer Only + + Overflow Marking + + Mentor + + (None) + @for (unitRole of unitStaff; track unitRole) { + + {{ unitRole.user.name }} + } + + Actions +
    + + +
    +
    + + + + + {{ staff.name }} + + + +
    diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts new file mode 100644 index 0000000000..5eab52fae3 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -0,0 +1,233 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {UnitRoleService} from 'src/app/api/services/unit-role.service'; +import {Unit} from 'src/app/api/models/unit'; +import {User} from 'src/app/api/models/doubtfire-model'; +import {UnitRole} from 'src/app/api/models/unit-role'; +import {MatTableDataSource} from '@angular/material/table'; +import {MatButtonToggleChange} from '@angular/material/button-toggle'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {MatSelectChange} from '@angular/material/select'; +import {TutorNotesModalService} from 'src/app/common/modals/tutor-notes-modal/tutor-notes-modal.service'; + +@Component({ + selector: 'unit-staff-editor', + templateUrl: 'unit-staff-editor.component.html', +}) +export class UnitStaffEditorComponent implements OnInit { + @Input() unit: Unit; + @Input() staff: User[]; + + temp = []; + users = []; + unitStaff: UnitRole[]; + filteredStaff: User[] = []; // Filtered staff members + searchTerm: string = ''; // Search term entered by the user + + displayedColumns: string[] = [ + 'name', + 'role', + 'main-convenor', + 'observer-only', + 'overflow-marking', + 'mentor', + 'actions', + ]; + dataSource = new MatTableDataSource(); + + // Inject services here + constructor( + private alertService: AlertService, + private unitRoleService: UnitRoleService, + private confirmationModalService: ConfirmationModalService, + private tutorNotesModal: TutorNotesModalService, + ) {} + + ngOnInit(): void { + // Subscribe to staff cache + this.unit.staffCache.values.subscribe((staff: UnitRole[]) => { + this.unitStaff = staff; + this.dataSource.data = staff; + }); + } + + onRoleChange(unitRole: UnitRole, event: MatButtonToggleChange) { + const role = event.value; + if (role !== 'Tutor' && role !== 'Convenor') { + return; + } + const roleId = role === 'Tutor' ? 2 : 3; // map however you like + this.changeRole(unitRole, roleId, role); + } + /** + * Changes the role of a staff member. + * + * @param UnitRole unitRole + * @param number role_id + * + * @returns void + */ + changeRole(unitRole: UnitRole, roleId: number, role: string) { + const previousRoleId = unitRole.roleId; + const previousRole = unitRole.role; + + unitRole.roleId = roleId; + unitRole.role = role; + this.unitRoleService.update(unitRole).subscribe({ + next: () => this.alertService.success('Role changed', 2000), + error: (response) => { + // Revert changes on error + unitRole.roleId = previousRoleId; + unitRole.role = previousRole; + this.alertService.error(response, 6000); + }, + }); + } + + toggleObserverOnly(unitRole: UnitRole) { + const previousValue = unitRole.observerOnly; + unitRole.observerOnly = !unitRole.observerOnly; + unitRole.roleId = unitRole.role === 'Tutor' ? 2 : 3; + this.unitRoleService.update(unitRole).subscribe({ + next: () => this.alertService.success('Observer status updated', 2000), + error: (response) => { + // Revert changes on error + unitRole.observerOnly = previousValue; + this.alertService.error(response, 6000); + }, + }); + } + + toggleCanOverflowMark(unitRole: UnitRole) { + const previousValue = unitRole.canMarkOverflowTasks; + unitRole.canMarkOverflowTasks = !unitRole.canMarkOverflowTasks; + unitRole.roleId = unitRole.role === 'Tutor' ? 2 : 3; + this.unitRoleService.update(unitRole).subscribe({ + next: () => this.alertService.success('Overflow marking permissions updated', 2000), + error: (response) => { + // Revert changes on error + unitRole.canMarkOverflowTasks = previousValue; + this.alertService.error(response, 6000); + }, + }); + } + + selectMentor(unitRole: UnitRole, event: MatSelectChange) { + const previousValue = unitRole.mentorId; + unitRole.mentorId = event.value; + unitRole.roleId = unitRole.role === 'Tutor' ? 2 : 3; + + this.unitRoleService.update(unitRole).subscribe({ + next: () => this.alertService.success('Mentor updated', 2000), + error: (response) => { + // Revert changes on error + unitRole.mentorId = previousValue; + this.alertService.error(response, 6000); + }, + }); + } + /** + * Changes who the `Main Convenor` of the unit is. + * + * @param UnitRole staff + * + * @returns void + */ + changeMainConvenor(staff: UnitRole) { + this.confirmationModalService.show( + 'Set Main Convenor', + `Do you want to make ${staff.user.name} the main convenor for this unit?`, + () => { + this.unit.changeMainConvenor(staff).subscribe({ + next: (_response) => this.alertService.success('Main convenor changed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + }, + ); + } + + /** + * Adds a staff member to the unit. + * + * @param User selectedStaff + * + * @returns void + */ + addSelectedStaff(selectedStaff: User) { + if (selectedStaff?.id) { + this.unit.addStaff(selectedStaff).subscribe({ + next: () => { + this.alertService.success('Staff member added', 2000); + this.searchTerm = ''; // Clear the input field + this.filterStaffList(); // Refilter the list + }, + error: (response) => this.alertService.error(response, 6000), + }); + } else { + this.alertService.error( + 'Unable to add staff member. Ensure they have a tutor or convenor account in User admin first', + ); + } + } + + /** + * Used in filtering the staff list. The `searchTerm` is bound to the auto-complete input in this class's template. + * + * @returns void + */ + filterStaffList(): void { + // `this.searchTerm` holds the selected staff member object from the dropdown OR the auto-complete input searchTerm (never at the same time). + // Thus, check the type here and exit early if string filtering is not needed. + if (typeof this.searchTerm !== 'string') { + return; + } + this.filteredStaff = this.staff.filter( + (staff) => + staff.matches(this.searchTerm.toLowerCase()) && // Find by name + !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id) && // Not already assigned to the unit + // Filter out students from the staff search + // NOTE: This is a hotfix to an issue where loading the inbox populates this.staff with students... + staff.isStaff, + ); + } + + /** + * Generates a human-readable name made up of the passed-in staff member's `first` and `last` names. + * + * @param User staff + * + * @returns void + */ + displayStaffName(staff: User): string { + return staff ? staff.name : ''; + } + + /** + * Removes a staff member from the unit. + * + * @param UnitRole staff + * + * @returns void + */ + removeStaff(staff: UnitRole) { + this.confirmationModalService.show( + 'Remove staff member', + `Are you sure you want to remove ${staff.user.name} from ${this.unit.code} ${this.unit.name}?`, + () => { + this.unitRoleService.delete(staff, {cache: this.unit.staffCache}).subscribe({ + next: () => this.alertService.success('Staff member removed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + }, + ); + } + + groupSetName(id: number) { + this.unit.groupSetsCache.get(id).name || 'Individual Work'; + } + + openTutorNotes(unitRole: UnitRole) { + unitRole.unit = this.unit; // HACK: ensure unit is mapped within the UnitRole + this.tutorNotesModal.show(null, unitRole); + } +} diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html deleted file mode 100644 index f8b38cecb0..0000000000 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html +++ /dev/null @@ -1,101 +0,0 @@ -
    - -
    -
    -

    Modify Unit Staff

    - Add staff members to the unit, assigning them a convenor or tutor role. -
    -
    -
    -
    This unit has no staff assigned
    -
    - - - - - - - - - - - - - - - - - - -
    NameRoleMain ConvenorActions
    - - {{staff.user.name}} -
    - - -
    -
    - - - -
    -
    -
    -
    - -
    -
    diff --git a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.html b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.html index 4797fff33b..ccba19f15a 100644 --- a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.html +++ b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.html @@ -15,14 +15,14 @@

    Enrolled Students

    - - + - + diff --git a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts index f29d36c605..c4402e82b3 100644 --- a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts @@ -3,16 +3,19 @@ import { csvResultModalService, unitStudentEnrolmentModal, } from './../../../../../ajs-upgraded-providers'; -import { ViewChild, Component, Input, Inject, AfterViewInit, OnDestroy } from '@angular/core'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatPaginator } from '@angular/material/paginator'; -import { HttpClient } from '@angular/common/http'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; -import { Project, ProjectService, Unit } from 'src/app/api/models/doubtfire-model'; -import { UIRouter } from '@uirouter/angular'; -import { Subscription } from 'rxjs'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {ViewChild, Component, Input, Inject, AfterViewInit, OnDestroy} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatPaginator} from '@angular/material/paginator'; +import {HttpClient} from '@angular/common/http'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {Project, ProjectService, Unit} from 'src/app/api/models/doubtfire-model'; +import {UIRouter} from '@uirouter/angular'; +import {Subscription} from 'rxjs'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {SpecConModalService} from 'src/app/common/modals/spec-con-modal/spec-con-modal.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; @Component({ selector: 'unit-students-editor', @@ -20,15 +23,24 @@ import { AlertService } from 'src/app/common/services/alert.service'; styleUrls: ['unit-students-editor.component.scss'], }) export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { - @ViewChild(MatTable, { static: false }) table: MatTable; - @ViewChild(MatSort, { static: false }) sort: MatSort; - @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; + @ViewChild(MatTable, {static: false}) table: MatTable; + @ViewChild(MatSort, {static: false}) sort: MatSort; + @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; @Input() unit: Unit; private subscriptions: Subscription[] = []; - columns: string[] = ['username', 'firstName', 'lastName', 'email', 'campus', 'tutorial', 'enrolled', 'goto']; + columns: string[] = [ + 'username', + 'firstName', + 'lastName', + 'email', + 'campus', + 'tutorial', + 'enrolled', + 'goto', + ]; dataSource: MatTableDataSource; // Calls the parent's constructor, passing in an object @@ -41,7 +53,9 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { @Inject(csvResultModalService) private csvResultModal: any, private fileDownloader: FileDownloaderService, private router: UIRouter, - private projectService: ProjectService + private projectService: ProjectService, + private specConModalService: SpecConModalService, + private sidekiqProgressModalService: SidekiqProgressModalService, ) {} // The paginator is inside the table @@ -54,13 +68,13 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { this.subscriptions.push( this.unit.studentCache.values.subscribe((students) => { this.dataSource.data = students; - }) + }), ); this.subscriptions.push( this.projectService.loadStudents(this.unit, true).subscribe(() => { // projects included in unit... - }) + }), ); } @@ -104,7 +118,11 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { } public gotoStudent(student: Project) { - this.router.stateService.go('projects/dashboard', { projectId: student.id, tutor: true, taskAbbr: '' }); + this.router.stateService.go('projects/dashboard', { + projectId: student.id, + tutor: true, + taskAbbr: '', + }); } enrolStudent() { @@ -115,15 +133,28 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { this.csvUploadModal.show( 'Upload Students to Enrol', 'Test message', - { file: { name: 'Enrol CSV Data', type: 'csv' } }, + {file: {name: 'Enrol CSV Data', type: 'csv'}}, this.unit.enrolStudentsCSVUrl, - (response: any) => { - // at least one student? - this.csvResultModal.show('Enrol Student CSV Results', response); - if (response.success.length > 0) { - this.unit.refreshStudents(true); + (response: SidekiqJob) => { + if (!response || !response.id) { + return this.alerts.error('Failed to start student import job', 6000); } - } + this.sidekiqProgressModalService + .show(`Importing Students: ${this.unit.code}`, response.id) + .subscribe({ + next: (job) => { + const result = JSON.parse(job.result); + this.csvResultModal.show('Enrol Student CSV Results', result); + // at least one student? + if (result.success.length > 0) { + this.unit.refreshStudents(true); + } + }, + error: (error) => { + console.error(error); + }, + }); + }, ); } @@ -131,7 +162,7 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { this.csvUploadModal.show( 'Upload Students to Withdraw', 'Test message', - { file: { name: 'Withdraw CSV Data', type: 'csv' } }, + {file: {name: 'Withdraw CSV Data', type: 'csv'}}, this.unit.withdrawStudentsCSVUrl, (response: any) => { // at least one student? @@ -139,7 +170,7 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { if (response.success.length > 0) { this.unit.refreshStudents(true); } - } + }, ); } @@ -148,4 +179,8 @@ export class UnitStudentsEditorComponent implements AfterViewInit, OnDestroy { this.fileDownloader.downloadFile(url, `${this.unit.code}-students.csv`); } + + public updateSpecCon(student: Project) { + this.specConModalService.show(student); + } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html index a2285a0969..c6a3eb74c6 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html @@ -1,43 +1,43 @@
    - - Start date to suggested completion date - - - - - - - + + Start Date + + + + Suggested date for students to begin the task. - - Suggestion completion date to final feedback - - - - + + Target Date + + + + Recommended target date for students to complete the task. + - - + + Final Feedback Date + + + + Final deadline for receiving feedback.
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html new file mode 100644 index 0000000000..7453a19525 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html @@ -0,0 +1,107 @@ +
    +
    +
    Username + Username {{ project.student.username }} First Name {{ project.student.firstName }} @@ -30,7 +30,7 @@

    Enrolled Students

    - +
    Last Name {{ project.student.lastName }} @@ -38,7 +38,7 @@

    Enrolled Students

    - +
    Email {{ project.student.email }} @@ -46,7 +46,7 @@

    Enrolled Students

    - +
    Campus @@ -54,7 +54,7 @@

    Enrolled Students

    - +
    Tutorial @@ -62,7 +62,7 @@

    Enrolled Students

    - +
    Enrolled Enrolled Students - + - +
    + + + +
    + + + + + + + + + + + + + + + + + +
    Discussion Prompt + @if (!editing(prompt)) { + {{ prompt.content }} + } @else { + + Discussion Prompt + + + } + Priority + @if (!editing(prompt)) { + {{ prompt.priorityLabel }} + } @else { +
    + + Priority + + + High + Medium + Low + + +
    + } +
    Actions +
    + @if (editing(prompt)) { + + + } @else { + + + } +
    +
    +
    + @if (!dataSource.data.length) { +
    No discussion prompts
    + } + @if (!creatingNewDiscussionPrompt) { +
    + +
    + } + + @if (creatingNewDiscussionPrompt) { + + +
    + + Discussion Prompt + + + + Priority + + + High + Medium + Low + + +
    +
    + + +
    +
    +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts new file mode 100644 index 0000000000..e22072d433 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts @@ -0,0 +1,158 @@ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatTableDataSource} from '@angular/material/table'; +import {Observable, Subscription} from 'rxjs'; +import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; +import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {Unit} from 'src/app/api/models/unit'; +import {DiscussionPromptService} from 'src/app/api/services/discussion-prompt.service'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-task-definition-discussion-prompts', + templateUrl: 'task-definition-discussion-prompts.component.html', + styleUrls: ['task-definition-discussion-prompts.component.scss'], +}) +export class TaskDefinitionDiscussionPromptsComponent + extends EntityFormComponent + implements OnInit, OnChanges +{ + @Input() taskDefinition: TaskDefinition; + @Input() staffView: boolean; + @Input() task: Task; + + displayedColumns: string[] = ['content', 'priority', 'actions']; + + private prereqSub?: Subscription; + + public dataSource = new MatTableDataSource(); + + creatingNewDiscussionPrompt: boolean = false; + + newDiscussionPromptContent: string; + newDiscussionPromptWeight: number = 2; + + constructor( + private taskDefinitionService: TaskDefinitionService, + private alertService: AlertService, + private taskPrerequisiteService: TaskPrerequisiteService, + private discussionPromptService: DiscussionPromptService, + ) { + super( + { + content: new UntypedFormControl('', [Validators.required]), + priority: new UntypedFormControl('', [Validators.required]), + }, + 'Discussion Prompt', + ); + } + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + public get prerequisites(): Observable { + return this.taskDefinition.taskPrerequisitesCache.values; + } + + ngOnInit(): void { + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if ( + changes.taskDefinition && + changes.taskDefinition.previousValue?.id !== changes.taskDefinition.currentValue?.id + ) { + this.prereqSub?.unsubscribe(); + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + this.fetchDiscussionPrompts(); + } + } + + private fetchDiscussionPrompts() { + const taskDefinition = this.taskDefinition; + if (!taskDefinition.id) { + return; + } + this.discussionPromptService.loadDiscussionPrompts(null, taskDefinition).subscribe({ + next: (data) => { + this.dataSource.data = data; + }, + error: (error) => { + this.alertService.error(`Failed to load discussion prompts: ${error}`, 6000); + }, + }); + } + + public addNewPrompt() { + const content = this.newDiscussionPromptContent; + const priority = this.newDiscussionPromptWeight; + this.discussionPromptService + .create( + { + task_definition_id: this.taskDefinition.id, + content: content, + priority: priority, + }, + { + cache: this.taskDefinition.discussionPromptsCache, + constructorParams: this.taskDefinition, + }, + ) + .subscribe({ + next: (_result) => { + this.cancelNewDiscussionPrompt(); + this.prereqSub?.unsubscribe(); + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + this.alertService.success(`Succesfully created prompt`, 3000); + }, + error: (error) => { + this.alertService.error(`Failed to create prompt: ${error}`, 6000); + }, + }); + } + + public deletePrompt(prompt: DiscussionPrompt) { + prompt.delete(); + } + + createNewDiscussionPrompt() { + this.creatingNewDiscussionPrompt = true; + } + + cancelNewDiscussionPrompt() { + this.creatingNewDiscussionPrompt = false; + this.newDiscussionPromptContent = ''; + this.newDiscussionPromptWeight = 2; + } + + submit() { + this.discussionPromptService + .put({ + id: this.selected.id, + task_definition_id: this.taskDefinition.id, + content: this.selected.content, + priority: this.selected.priority, + }) + .subscribe({ + next: (_response) => { + this.cancelEdit(); + this.alertService.success('Successfully saved prompt', 3000); + }, + error: (error) => { + this.alertService.error(`Failed to update prompt: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 5bbf1e64e5..567758a0ad 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -1,146 +1,175 @@ -
    -
    -
    -
    - 1 -
    -
    +
    +

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }}

    + +
    -
    -

    Task details

    -

    Name the task and set target grade

    -
    - -
    +
    +
    + -
    -
    -
    - 2 -
    -
    +
    +
    +

    Task Details

    +

    Name the task and set target grade

    + +
    + + +
    +

    Task Learning Outcomes

    +

    Add learning outcomes for this task

    + +
    + -
    -

    Inbox

    -

    +

    +

    Inbox

    +

    Who assesses {{ unit.hasGroupwork() ? 'and submits ' : '' }}this task?

    -
    - -
    -
    -
    + + + -
    -
    -
    - 3 -
    -
    +
    +

    Due Dates

    +

    When is the task due?

    + +
    + -
    -

    Due dates

    -

    When is this task due?

    -
    - -
    -
    -
    +
    +

    Upload Requirements

    +

    What do students need to upload?

    + +
    + -
    -
    -
    - 4 -
    -
    +
    +

    Task Resources

    +

    Upload task descriptions and resources

    + +
    + -
    -

    Upload requirements

    -

    What do students need to upload?

    -
    - -
    -
    -
    - -
    -
    -
    - 5 -
    -
    +
    +

    Prerequisite Tasks

    +

    + Select which tasks need to be submitted before + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + can be submitted +

    + + +
    + -
    -

    - Task description and resources -

    -

    Upload task descriptions and resources

    -
    - -
    -
    -
    +
    +

    Discussion Prompts

    +

    + Discussion prompts for tutors to use when discussing student tasks in class +

    + + +
    + -
    -
    -
    - 6 -
    -
    +

    Task Assessment Automation

    +

    Configure automated assessment

    + + + + } -
    -

    - Task assessment automation -

    -

    Automation is not enabled

    -

    - Configure automated assessment +

    +

    SCORM Test

    +

    + Upload the corresponding SCORM 2004 test (e.g. Numbas)

    -
    - -
    -
    -
    + + + -
    -
    -
    - 7 -
    -
    +
    +

    Optional Settings

    +

    Apply other options

    + +
    -
    -

    Optional settings

    -

    Configure automated assessment

    - - - - Options - - - - -
    + + +
    -
    - +
    +
    + +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss index 05e8bffddc..e69de29bb2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss @@ -1,10 +0,0 @@ -.mat-toolbar { - background-color: white; - // position: fixed; - // bottom: 0; - // width: 100%; -} - -.form-group { - -} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts index 88f7ccfe2d..1da5af76f1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts @@ -1,24 +1,170 @@ -import { Component, Input } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import { + AfterViewInit, + Component, + ElementRef, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + QueryList, + SimpleChanges, + ViewChild, + ViewChildren, +} from '@angular/core'; +import {Subscription} from 'rxjs'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; + +type TaskDefinitionSectionId = + | 'task-details' + | 'task-learning-outcomes' + | 'inbox' + | 'due-dates' + | 'upload-requirements' + | 'task-resources' + | 'prerequisite-tasks' + | 'discussion-prompts' + | 'task-assessment-automation' + | 'scorm-test' + | 'optional-settings'; + +interface TaskDefinitionSection { + id: TaskDefinitionSectionId; + label: string; +} @Component({ selector: 'f-task-definition-editor', templateUrl: 'task-definition-editor.component.html', styleUrls: ['task-definition-editor.component.scss'], }) -export class TaskDefinitionEditorComponent { +export class TaskDefinitionEditorComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { @Input() taskDefinition: TaskDefinition; @Input() unit: Unit; + @ViewChild('sectionScrollContainer') sectionScrollContainer: ElementRef; + @ViewChildren('sectionElement') sectionElements: QueryList>; + + public overseerEnabled: boolean = false; + public activeSectionId: TaskDefinitionSectionId = 'task-details'; + public readonly sectionList: TaskDefinitionSection[] = [ + {id: 'task-details', label: 'Task Details'}, + {id: 'task-learning-outcomes', label: 'Task Learning Outcomes'}, + {id: 'inbox', label: 'Inbox'}, + {id: 'due-dates', label: 'Due Dates'}, + {id: 'upload-requirements', label: 'Upload Requirements'}, + {id: 'task-resources', label: 'Task Resources'}, + {id: 'prerequisite-tasks', label: 'Prerequisite Tasks'}, + {id: 'discussion-prompts', label: 'Discussion Prompts'}, + {id: 'task-assessment-automation', label: 'Task Assessment Automation'}, + {id: 'scorm-test', label: 'SCORM Test'}, + {id: 'optional-settings', label: 'Optional Settings'}, + ]; + + private sectionElementMap = new Map(); + private sectionChangesSubscription?: Subscription; + private overseerEnabledSubscription?: Subscription; + private readonly scrollTopOffsetPx: number = 112; + + constructor( + private taskDefinitionService: TaskDefinitionService, + private alerts: AlertService, + private constants: DoubtfireConstants, + ) {} - constructor(private taskDefinitionService: TaskDefinitionService, private alerts: AlertService, private constants: DoubtfireConstants) { - constants.IsOverseerEnabled.subscribe((enabled) => (this.overseerEnabled = enabled && this.unit.overseerEnabled)); + public ngOnInit() { + this.overseerEnabledSubscription = this.constants.IsOverseerEnabled.subscribe((enabled) => { + this.overseerEnabled = enabled && this.unit.overseerEnabled; + this.ensureActiveSectionIsVisible(); + this.rebuildSectionElementMap(); + }); } - public overseerEnabled: boolean = false; + public ngAfterViewInit() { + this.rebuildSectionElementMap(); + this.sectionChangesSubscription = this.sectionElements.changes.subscribe(() => { + this.rebuildSectionElementMap(); + this.syncActiveSectionOnScroll(); + }); + queueMicrotask(() => this.syncActiveSectionOnScroll()); + } + + public ngOnChanges(changes: SimpleChanges) { + if (changes.taskDefinition && !changes.taskDefinition.firstChange) { + this.ensureActiveSectionIsVisible(); + queueMicrotask(() => this.syncActiveSectionOnScroll()); + } + } + + public ngOnDestroy() { + this.sectionChangesSubscription?.unsubscribe(); + this.overseerEnabledSubscription?.unsubscribe(); + } + + public get visibleSections(): TaskDefinitionSection[] { + return this.overseerEnabled + ? this.sectionList + : this.sectionList.filter((section) => section.id !== 'task-assessment-automation'); + } + + public scrollToSection(sectionId: TaskDefinitionSectionId) { + this.activeSectionId = sectionId; + + const container = this.sectionScrollContainer?.nativeElement; + const target = this.sectionElementMap.get(sectionId); + + if (!container || !target) return; + + if (this.isContainerScrollable(container)) { + const targetTop = this.getSectionTopInContainer(container, target); + container.scrollTo({ + top: Math.max(targetTop - 8, 0), + behavior: 'smooth', + }); + return; + } + + target.scrollIntoView({ + behavior: 'smooth', + block: 'start', + }); + } + + public syncActiveSectionOnScroll() { + const container = this.sectionScrollContainer?.nativeElement; + if (!container) return; + + if (!this.isContainerScrollable(container)) { + this.syncActiveSectionOnWindowScroll(); + return; + } + + const scrollPosition = container.scrollTop + 48; + let nextActiveSection = this.visibleSections[0]?.id; + + this.visibleSections.forEach((section) => { + const sectionElement = this.sectionElementMap.get(section.id); + if ( + sectionElement && + this.getSectionTopInContainer(container, sectionElement) <= scrollPosition + ) { + nextActiveSection = section.id; + } + }); + + if (nextActiveSection) { + this.activeSectionId = nextActiveSection; + } + } + + @HostListener('window:scroll') + @HostListener('window:resize') + public onWindowScroll() { + this.syncActiveSectionOnScroll(); + } public save() { this.taskDefinition.save().subscribe({ @@ -29,4 +175,49 @@ export class TaskDefinitionEditorComponent { error: (message) => this.alerts.error(message), }); } + + private ensureActiveSectionIsVisible() { + if (!this.visibleSections.some((section) => section.id === this.activeSectionId)) { + this.activeSectionId = this.visibleSections[0]?.id ?? 'task-details'; + } + } + + private rebuildSectionElementMap() { + this.sectionElementMap.clear(); + + this.sectionElements?.forEach((sectionElementRef) => { + const nativeElement = sectionElementRef.nativeElement; + const sectionId = nativeElement.getAttribute('data-section-id') as TaskDefinitionSectionId; + + if (sectionId) { + this.sectionElementMap.set(sectionId, nativeElement); + } + }); + } + + private getSectionTopInContainer(container: HTMLElement, sectionElement: HTMLElement): number { + const containerRect = container.getBoundingClientRect(); + const sectionRect = sectionElement.getBoundingClientRect(); + return container.scrollTop + (sectionRect.top - containerRect.top); + } + + private syncActiveSectionOnWindowScroll() { + const threshold = this.scrollTopOffsetPx + 12; + let nextActiveSection = this.visibleSections[0]?.id; + + this.visibleSections.forEach((section) => { + const sectionElement = this.sectionElementMap.get(section.id); + if (sectionElement && sectionElement.getBoundingClientRect().top <= threshold) { + nextActiveSection = section.id; + } + }); + + if (nextActiveSection) { + this.activeSectionId = nextActiveSection; + } + } + + private isContainerScrollable(container: HTMLElement): boolean { + return container.scrollHeight > container.clientHeight + 1; + } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html index a479f20ce3..5d00855580 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html @@ -1,32 +1,57 @@ -
    -
    +
    +
    Restrict updates - This task will be locked once it goes into a staff-allocated status. Students will not be able to resubmit, even - if placed on the fix status. + This task will be locked once it goes into a staff-allocated status. Students will not be able + to resubmit, even if placed on the fix status.
    -
    - Graded +
    + Assess in Portfolio Only - Provide a grade along with the complete or discuss status. We recommend avoiding this practice. + This task cannot be signed off as complete and will only be assessed in the final portfolio. + Tutors can leave feedback and return it to the "Working on it" state. Students must then + update the status to "Assess in Portfolio" to ensure it's included in their portfolio.
    -
    +
    + + Requires Discussion + + + Tutors cannot mark this task as complete unless it has first been marked as discussed in + class. + +
    + +
    + Graded + + Provide a grade along with the complete or discuss status. We recommend avoiding this + practice. + +
    + +
    - Maximum Score - + Quality Stars + - Provide a score alongside the task status. We recommend avoiding this practice. + Provide a number of stars alongside the task status. Make sure you have a clear reason for + each star within your task description.
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts index 7fc62fa813..80a26895c1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts @@ -1,6 +1,7 @@ -import { Component, Input } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; +import {Component, Input} from '@angular/core'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ selector: 'f-task-definition-options', @@ -9,8 +10,28 @@ import { Unit } from 'src/app/api/models/unit'; }) export class TaskDefinitionOptionsComponent { @Input() taskDefinition: TaskDefinition; + constructor(private confirmationModal: ConfirmationModalService) {} public get unit(): Unit { return this.taskDefinition?.unit; } + + public onToggleAssessInPortfolioOnly() { + if (!this.taskDefinition.assessInPortfolioOnly) { + return; + } + + setTimeout(() => { + this.taskDefinition.assessInPortfolioOnly = false; + console.log(this.taskDefinition.assessInPortfolioOnly); + + this.confirmationModal.show( + `Enable Assess in Portfolio Only?`, + `Enabling Assess in Portfolio Only will update all overdue tasks for ${this.taskDefinition.name} to the Assess in Portfolio state`, + () => { + this.taskDefinition.assessInPortfolioOnly = true; + }, + ); + }); + } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html new file mode 100644 index 0000000000..1d6a563570 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html @@ -0,0 +1,14 @@ +
    +
    +

    {{ data.taskDefinition.abbreviation }} {{ data.taskDefinition.name }}

    +

    Overseer script

    +
    +
    + +
    + @if (!loading) { + + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts new file mode 100644 index 0000000000..128e2410f0 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -0,0 +1,61 @@ +import {HttpClient} from '@angular/common/http'; +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {CodeModel} from '@ngstack/code-editor'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.service'; + +@Component({ + selector: 'f-overseer-script-editor-modal', + templateUrl: './overseer-script-editor-modal.component.html', + styleUrls: ['./overseer-script-editor-modal.component.scss'], +}) +export class OverseerScriptEditorModalComponent implements OnInit { + constructor( + @Inject(MAT_DIALOG_DATA) public data: OverseerScriptEditorModalData, + public dialogRef: MatDialogRef, + private httpClient: HttpClient, + private alertService: AlertService, + ) {} + + public model: CodeModel = { + language: 'shell', + uri: 'run.sh', + value: '', + }; + + scriptContent: string; + + loading: boolean = false; + ngOnInit() { + this.loading = true; + this.httpClient + .get(this.data.taskDefinition.taskOverseerExecutionScriptUrl) + .subscribe((data: string) => { + this.model.value = data; + this.loading = false; + }); + } + + save() { + const scriptOriginal = this.model.value; + const scriptEncoded = this.base64UrlEncode(scriptOriginal); + + this.httpClient + .put(this.data.taskDefinition.taskOverseerExecutionScriptUrl, { + script_content: scriptEncoded, + }) + .subscribe({ + next: (_result) => { + this.dialogRef.close(); + }, + error: (error) => { + this.alertService.error(`Failed to save script: ${error}`, 6000); + }, + }); + } + + private base64UrlEncode(str) { + return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts new file mode 100644 index 0000000000..c238db3eaf --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts @@ -0,0 +1,28 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {OverseerScriptEditorModalComponent} from './overseer-script-editor-modal.component'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; + +export interface OverseerScriptEditorModalData { + taskDefinition: TaskDefinition; +} + +@Injectable({ + providedIn: 'root', +}) +export class OverseerScriptEditorModalService { + constructor(public dialog: MatDialog) {} + + public show(taskDefinition: TaskDefinition) { + const _dialogRef = this.dialog.open< + OverseerScriptEditorModalComponent, + OverseerScriptEditorModalData + >(OverseerScriptEditorModalComponent, { + data: { + taskDefinition: taskDefinition, + }, + width: '100%', + maxWidth: '1200px', + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index 92ef121ff3..459dea4266 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -1,40 +1,405 @@
    - - Automation Enabled - +
    + + Automation Enabled + +
    + + You can add or modify Overseer steps while keeping this unchecked and use the test submission + feature. Once everything is ready, enable automation to apply it to all student submissions. + +
    Docker Image @for (image of images | async; track image) { - {{ image.description }} -} + {{ image.description }} + } Docker image for Overseer - + + @if (taskDefinition.hasTaskAssessmentResources) { +
    + + + +
    + + @if (showOverseerResourcesEditor) { +
    + @if (isLoadingOverseerResourcesArchive) { +
    + Loading Overseer Resources archive... +
    + } @else if (overseerResourcesArchive) { + + } @else { +
    + Unable to load Overseer Resources archive. +
    + } +
    + } + } -
    +
    + +
    + +@if (taskDefinition.overseerImageId) { + @if (!taskDefinitionHasChanges()) { +
    +
    + @if (this.selectedOverseerStep) { + + + } +
    +
    + + + +
    +
    Overseer Steps
    + @if (!newOverseerStep) { + + } +
    +
    + @for (step of overseerSteps; track step.id) { +
    + drag_indicator + {{ step.sortOrder }}. {{ step.name ?? 'Untitled Step' }} +
    + } + @if (newOverseerStep) { +
    + {{ newOverseerStep.sortOrder }}. {{ newOverseerStep.name || 'Untitled Step' }} +
    + } +
    +
    + + @if (selectedOverseerStep) { + + +
    + + Step Name + + Visible to staff only + + + Description + + Visible to staff only + +
    + + + Step Type + + Custom Script + Input/Output + + + + @if (selectedOverseerStep.stepType === 'output_diff') { +
    +
    + + Script Input File + + + (none) + @for (file of taskDefinition.overseerResourceFiles; track file) { + {{ file }} + } + + The selected file will be passed as standard input to the program when it + runs. + + + + Show input file to student + +
    +
    + + Expected Output File + + (none) + @for (file of taskDefinition.overseerResourceFiles; track file) { + {{ file }} + } + + Program output must exactly match this file to pass. + + + Show expected output file to student + +
    + Partial Output Comparison +
    + + If enabled, test passes if the expected output appears anywhere in the + student's output. Otherwise, only exact matches pass. + +
    +
    + } + +
    +
    Execution Script
    + + Language + + @for (language of getLanguages; track language) { + {{ + language.id ?? language.aliases?.[0] ?? language.id + }} + } + + Visual use only + +
    + +
    + + + @if (selectedOverseerStep.stepType === 'status_check') { + This step passes only if the script exits with status 0. Any non-zero exit code + marks the step as failed. + } @else if (selectedOverseerStep.stepType === 'output_diff') { + The script output is compared against the expected output. If noisy warnings + cause failures, move that logic into a separate step. + } + +
    + + Time Limit (s) + + How long the code can execute for before overseer automatically kills the + process. A timeout will result in a failed test (Exit status 124) + +
    +
    + +
    + Halt on success + + @if (selectedOverseerStep.haltOnSuccess) { + + Status on Success + + No Change + @for (status of statusKeys; track status) { + {{ statusName(status) }} + } + + + } +
    +
    + +
    + +
    + + Halt on failure + + @if (selectedOverseerStep.haltOnFailure) { + + + Status on Fail + + No Change + @for (status of statusKeys; track status) { + {{ statusName(status) }} + } + + + } +
    +
    +
    + + +
    + + + Test Name + + Shown to student in overseer report + + + Description + + Shown to student in overseer report + +
    + + Feedback message + + Feedback to provide to the student if the task failed. You can leave this blank + and a default will message will be used instead. + + +
    + Enabled +
    + + If disabled, this step will not run and will not appear in the Overseer report for + students. + +
    + +
    + Show output +
    + + When enabled, students can see this step’s standard output, including script + output, program output, and compile errors. + +
    +
    +
    + } @else { +
    + No steps selected + tab_unselected +
    + } +
    +
    + } @else { +
    + Please save the task definition before configuring the overseer steps. +
    + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss index e69de29bb2..ff10c528b0 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss @@ -0,0 +1,50 @@ +.example-list { + width: 300px; + max-width: 100%; + border: solid 1px #ccc; + min-height: 50px; + height: 100%; + display: block; + background: white; + // border-radius: 4px; + overflow: hidden; +} + +.example-box { + padding: 20px 10px; + border-bottom: solid 1px #ccc; + height: 50px; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + // justify-content: space-between; + box-sizing: border-box; + cursor: pointer; + background: white; + font-size: 14px; + font-family: sans-serif; + user-select: none; +} + +.cdk-drag-preview { + border: none; + box-sizing: border-box; + border-radius: 4px; + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} +.cdk-drag-placeholder { + opacity: 0; +} +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} +.example-box:last-child { + border: none; +} +.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts index f9b30dde0d..1d539cce29 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts @@ -1,39 +1,244 @@ -import { Component, Input, OnChanges } from '@angular/core'; -import { Observable } from 'rxjs'; +import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; +import {HttpClient, HttpResponse} from '@angular/common/http'; +import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; +import {Observable} from 'rxjs'; import { OverseerAssessment, OverseerImage, OverseerImageService, Task, + TaskService, + TaskStatusEnum, User, UserService, } from 'src/app/api/models/doubtfire-model'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; -import { TaskAssessmentModalService } from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { TaskSubmissionService } from 'src/app/common/services/task-submission.service'; - +import {OverseerStep} from 'src/app/api/models/overseer/overseer-step'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {OverseerStepService} from 'src/app/api/services/overseer-step.service'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; +import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/overseer-script-editor-modal.service'; +import * as monaco from 'monaco-editor'; +import {MatSelectChange} from '@angular/material/select'; @Component({ selector: 'f-task-definition-overseer', templateUrl: 'task-definition-overseer.component.html', styleUrls: ['task-definition-overseer.component.scss'], }) -export class TaskDefinitionOverseerComponent implements OnChanges { +export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { @Input() taskDefinition: TaskDefinition; + @ViewChild('editor') editorComponent; + public currentUserTask: Task; + editorOptions = { + theme: 'vs', + language: 'shell', + renderMinimap: false, + + minimap: { + enabled: false, + }, + }; + + public stepType: 'status_check' | 'output_diff' = 'status_check'; + public visibility = 'public'; + public showOverseerResourcesEditor = false; + public isLoadingOverseerResourcesArchive = false; + public overseerResourcesArchive: Blob | File | null = null; constructor( + private http: HttpClient, private alerts: AlertService, private overseerImageService: OverseerImageService, private modalService: TaskAssessmentModalService, private submissions: TaskSubmissionService, private userService: UserService, - private taskDefinitionService: TaskDefinitionService + private taskDefinitionService: TaskDefinitionService, + private fileDownloaderService: FileDownloaderService, + private overseerScriptEditorModal: OverseerScriptEditorModalService, + private overseerStepService: OverseerStepService, + private taskService: TaskService, ) {} + public get statusKeys() { + return this.taskService.statusKeys; + } + + public statusName(status: TaskStatusEnum) { + return this.taskService.statusLabels.get(status); + } + + public selectedOverseerStep: OverseerStep = null; + public newOverseerStep: OverseerStep = null; + + public overseerSteps: OverseerStep[] = []; + + onRunCommandChange(step: OverseerStep, value: string) { + step.runCommand = `b64:${this.base64UrlEncode(value)}`; + } + + private base64UrlEncode(str) { + return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + } + + selectStep(step: OverseerStep) { + this.selectedOverseerStep = step; + setTimeout(() => { + const editor = this.editorComponent?._editor; + if (editor) { + editor.revealLine(1); + editor.setScrollPosition({scrollTop: 0}); + } + }); + } + + addStep() { + this.newOverseerStep = new OverseerStep(this.taskDefinition); + this.newOverseerStep.stepType = 'status_check'; + this.newOverseerStep.timeout = 30; + this.newOverseerStep.enabled = true; + this.newOverseerStep.showStdout = true; + this.newOverseerStep.statusOnFailure = 'no_change'; + this.newOverseerStep.statusOnSuccess = 'no_change'; + this.newOverseerStep.commandLanguage = 'shell'; + this.newOverseerStep.decodedRunCommand = '#!/bin/bash\n\n'; + this.newOverseerStep.runCommand = '#!/bin/bash\n\n'; + this.newOverseerStep.showExpectedOutput = true; + + this.newOverseerStep.sortOrder = this.taskDefinition.overseerStepsCache.currentValues.length; + this.selectedOverseerStep = this.newOverseerStep; + } + + getFeedbackMessagePlaceholder() { + // If the feedback message is blank, this is what will automatically be used + // (If this changes, ensure to update it in AcceptOverseerJob) + switch (this.selectedOverseerStep.stepType) { + case 'status_check': + return 'This test did not complete successfully. Check the output for any errors.'; + case 'output_diff': + return 'Your output did not match the expected result.'; + } + } + + ngOnInit(): void { + this.taskDefinition.overseerStepsCache.values.subscribe((steps) => { + this.overseerSteps = [...steps]; + }); + } + + public get getLanguages() { + return monaco?.languages.getLanguages() ?? []; + } + + onLanguageChange(event: MatSelectChange) { + const value = event.value; + this.editorOptions.language = value; + this.editorOptions = {...this.editorOptions}; + } + + drop(event: CdkDragDrop) { + if (this.newOverseerStep) { + this.alerts.error('Please save changes before re-ordering steps', 3000); + return; + } + moveItemInArray(this.overseerSteps, event.previousIndex, event.currentIndex); + // TODO: open endpoint to update sort orders in a single request + for (let i = 0; i < this.overseerSteps.length; i++) { + const step = this.taskDefinition.overseerStepsCache.get(this.overseerSteps[i].id); + if (step.sortOrder === i) { + // Ignore if no change + continue; + } + step.sortOrder = i; + this.overseerStepService + .update( + { + id: step.id, + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: step, + constructorParams: this.taskDefinition, + }, + ) + .subscribe({ + next: () => { + // console.log('updated!'); + }, + error: (error) => { + this.alerts.error(`Failed to update order of steps: ${error}`, 6000); + }, + }); + } + } + + deleteStep() { + if (this.selectedOverseerStep && this.selectedOverseerStep === this.newOverseerStep) { + this.newOverseerStep = null; + this.selectedOverseerStep = null; + return; + } + this.selectedOverseerStep?.delete(); + this.selectedOverseerStep = null; + } + + saveStep() { + if (!this.selectedOverseerStep.id) { + // this.newOverseerStep.runCommand = this.model.value; + this.overseerStepService + .create( + { + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: this.newOverseerStep, + }, + ) + .subscribe({ + next: (result) => { + this.alerts.success('Added overseer step', 3000); + result.taskDefinition = this.taskDefinition; + this.taskDefinition.overseerStepsCache.add(result); + this.selectStep(result); + this.newOverseerStep = null; + }, + error: (error) => { + console.error(error); + this.alerts.error(error, 3000); + }, + }); + } else { + this.overseerStepService + .update( + { + id: this.selectedOverseerStep.id, + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: this.selectedOverseerStep, + cache: this.taskDefinition.overseerStepsCache, + }, + ) + .subscribe({ + next: (result) => { + this.alerts.success('Saved overseer step', 3000); + }, + error: (error) => { + console.error(error); + this.alerts.error(error, 3000); + }, + }); + } + } + public get overseerEnabled(): boolean { return this.unit.overseerEnabled; } @@ -50,12 +255,24 @@ export class TaskDefinitionOverseerComponent implements OnChanges { return this.userService.currentUser; } - public ngOnChanges() { + public taskDefinitionHasChanges(): boolean { + return this.taskDefinition.hasChanges(this.taskDefinitionService.mapping); + } + + public ngOnChanges(changes: SimpleChanges) { const proj = this.unit.findProjectForUsername(this.currentUser.username); if (proj) { this.currentUserTask = proj.findTaskForDefinition(this.taskDefinition.id); this.hasAnySubmissions(); } + if (changes['taskDefinition']) { + this.taskDefinition.overseerStepsCache.values.subscribe((steps) => { + this.overseerSteps = [...steps]; + }); + this.showOverseerResourcesEditor = false; + this.isLoadingOverseerResourcesArchive = false; + this.overseerResourcesArchive = null; + } } testSubmission() { @@ -65,12 +282,16 @@ export class TaskDefinitionOverseerComponent implements OnChanges { this.currentUserTask.definition = this.taskDefinition; this.currentUserTask.status = 'ready_for_feedback'; this.currentUserTask.id = this.taskDefinition.id; // set a default id... - this.hasAnySubmissions(); + // this.hasAnySubmissions(); } this.currentUserTask.presentTaskSubmissionModal(this.currentUserTask.status, false, true); } + editScript() { + this.overseerScriptEditorModal.show(this.taskDefinition); + } + testSubmissionHistory() { this.modalService.show(this.currentUserTask); } @@ -86,16 +307,79 @@ export class TaskDefinitionOverseerComponent implements OnChanges { }); } + public removeOverseerResources() { + this.taskDefinition.deleteOverseerResources().subscribe({ + next: () => { + this.alerts.success('Deleted Overseer Resources', 2000); + this.taskDefinition.hasTaskAssessmentResources = false; + this.showOverseerResourcesEditor = false; + this.overseerResourcesArchive = null; + }, + }); + } + + public downloadOverseerResources() { + this.fileDownloaderService.downloadFile( + this.taskDefinition.getOverseerResourcesUrl(), + this.taskDefinition.name + '.zip', + ); + } + public uploadOverseerResources(files: FileList) { - const validFiles = Array.from(files as ArrayLike).filter((f) => f.type === 'application/zip'); + const validFiles = Array.from(files as ArrayLike).filter( + (f) => f.type === 'application/zip' || f.type === 'application/x-zip-compressed', + ); if (validFiles.length > 0) { const file = validFiles[0]; - this.taskDefinitionService.uploadTaskResources(this.taskDefinition, file).subscribe({ - next: () => this.alerts.success('Uploaded task sheet', 2000), + this.taskDefinitionService.uploadOverseerResources(this.taskDefinition, file).subscribe({ + next: (resourceFiles) => { + this.alerts.success('Uploaded Overseer Resources', 2000); + this.taskDefinition.hasTaskAssessmentResources = true; + this.taskDefinition.overseerResourceFiles = [...resourceFiles]; + this.overseerResourcesArchive = file; + }, error: (message) => this.alerts.error(message, 6000), }); } else { - this.alerts.error('Please drop a PDF to upload for this task', 6000); + this.alerts.error('Please drop a zip with scripts for this task to upload', 6000); } } + + public toggleOverseerResourcesEditor() { + this.showOverseerResourcesEditor = !this.showOverseerResourcesEditor; + if ( + this.showOverseerResourcesEditor && + !this.overseerResourcesArchive && + this.taskDefinition?.hasTaskAssessmentResources + ) { + this.loadOverseerResourcesArchive(); + } + } + + public onOverseerResourcesArchiveSaved(response: HttpResponse) { + this.taskDefinition.hasTaskAssessmentResources = true; + + if (Array.isArray(response.body)) { + this.taskDefinition.overseerResourceFiles = response.body.filter( + (file): file is string => typeof file === 'string', + ); + } + } + + private loadOverseerResourcesArchive() { + this.isLoadingOverseerResourcesArchive = true; + this.http.get(this.taskDefinition.getOverseerResourcesUrl(), {responseType: 'blob'}).subscribe({ + next: (archiveBlob) => { + this.overseerResourcesArchive = archiveBlob; + }, + error: (error) => { + this.isLoadingOverseerResourcesArchive = false; + this.showOverseerResourcesEditor = false; + this.alerts.error(`Failed to load Overseer Resources Zip: ${error?.error?.error ?? error}`); + }, + complete: () => { + this.isLoadingOverseerResourcesArchive = false; + }, + }); + } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html new file mode 100644 index 0000000000..cf4faacbe4 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html @@ -0,0 +1,114 @@ +
    +
    + + + + + + + + + + + + + + + } @else { + + } + + + + +
    Task + {{ link.prerequisite?.abbreviation }} {{ link.prerequisite?.name }} + + @if (staffView) { + Minimum Required Status + } @else { + Current Status + } + + @if (!staffView) { + + } @else { + @if (link.taskStatus) { + + + {{ state.label }} + + + } + } + + @if (staffView) { + Actions + } @else { + Required Status + } + + @if (staffView) { + + +
    +
    + + @if (staffView) { +
    + + + + + @for (td of filteredTaskDefs; track td) { + {{ td.abbreviation }} - {{ td.name }} + } + + +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts new file mode 100644 index 0000000000..680187d594 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts @@ -0,0 +1,241 @@ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {MatTableDataSource} from '@angular/material/table'; +import {Observable, Subscription} from 'rxjs'; +import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {TaskStatusEnum} from 'src/app/api/models/task-status'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-task-definition-prerequisites', + templateUrl: 'task-definition-prerequisites.component.html', + styleUrls: ['task-definition-prerequisites.component.scss'], +}) +export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { + @Input() taskDefinition: TaskDefinition; + @Input() staffView: boolean; + @Input() task: Task; + + displayedColumns: string[] = ['task-definition', 'minimum-required-state', 'actions']; + + private prereqSub?: Subscription; + + public dataSource = new MatTableDataSource(); + + selectedTaskPrerequisite: TaskDefinition | null = null; + searchCtrl = new FormControl(''); + + // All other task definitions in the unit (exclude the current one) + filteredTaskDefs: TaskDefinition[] = []; + + public readonly STATES: Partial> = { + ready_for_feedback: 1, + assess_in_portfolio: 1, + discuss: 2, + attention_required: 0, + demonstrate: 2, + complete: 3, + }; + + public readonly stateOptions = [ + {value: 'ready_for_feedback', label: 'Ready for Feedback'}, + {value: 'discuss', label: 'Discuss'}, + {value: 'complete', label: 'Complete'}, + ]; + + constructor( + private taskDefinitionService: TaskDefinitionService, + private alertService: AlertService, + private taskPrerequisiteService: TaskPrerequisiteService, + ) {} + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + public get prerequisites(): Observable { + return this.taskDefinition.taskPrerequisitesCache.values; + } + + ngOnInit(): void { + this.searchCtrl.valueChanges.subscribe((value: string | TaskDefinition) => { + const search = (typeof value === 'string' ? value : value?.name || '').toLowerCase(); + this.filterTaskDefs(search); + }); + + this.prereqSub = this.taskDefinition.taskPrerequisitesCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + + // this.fetchTaskPrerequisites(); + } + + private mapPrerequisites(taskDefinition: TaskDefinition) { + const prerequisites = taskDefinition.taskPrerequisitesCache.currentValues; + const definitions = taskDefinition.unit.taskDefinitions; + for (const prerequisite of prerequisites) { + prerequisite.taskDefinition = definitions.find( + (td) => td.id === prerequisite.taskDefinitionId, + ); + prerequisite.prerequisite = definitions.find((td) => td.id === prerequisite.prerequisiteId); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if ( + changes.taskDefinition && + changes.taskDefinition.previousValue?.id !== changes.taskDefinition.currentValue?.id + ) { + this.filterTaskDefs(this.searchCtrl.value ?? ''); + this.prereqSub?.unsubscribe(); + this.prereqSub = this.taskDefinition.taskPrerequisitesCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + this.fetchTaskPrerequisites(); + } + } + + private fetchTaskPrerequisites() { + const taskDefinition = this.taskDefinition; + if (!taskDefinition.id) { + return; + } + this.taskPrerequisiteService + .query( + { + unitId: this.unit.id, + taskDefId: taskDefinition.id, + }, + { + cache: taskDefinition.taskPrerequisitesCache, + }, + ) + .subscribe({ + next: (data) => { + for (const prereq of data) { + if (prereq.taskDefinitionId !== taskDefinition.id) { + continue; + } + taskDefinition.taskPrerequisitesCache.getOrCreate( + prereq.id, + this.taskPrerequisiteService, + prereq, + ); + } + this.mapPrerequisites(taskDefinition); + this.filterTaskDefs(this.searchCtrl.value ?? ''); + }, + error: (error) => { + this.alertService.error( + `Failed to fetch prerequisites for task definition: ${error}`, + 6000, + ); + }, + }); + } + + private filterTaskDefs(search: string) { + this.filteredTaskDefs = this.taskDefinition.unit.taskDefinitionCache.currentValues + // Hide self from the list + .filter((td) => td.id !== this.taskDefinition.id) + // Hide tasks already added as a prerequisite + .filter( + (td) => + !this.taskDefinition.taskPrerequisitesCache.currentValues.some( + (p: TaskPrerequisite) => p.prerequisite.id === td.id, + ), + ) + // Higher target grades can not be a prerequisite + .filter((td) => td.targetGrade <= this.taskDefinition.targetGrade) + // Tasks with a later due date can not be a prerequisite + // .filter((td) => td.targetDate <= this.taskDefinition.targetDate) + // Search filter + .filter( + (td) => + td.name.toLowerCase().includes(search) || td.abbreviation.toLowerCase().includes(search), + ); + } + + displayFn(td: TaskDefinition): string { + return td && td.abbreviation ? `${td.abbreviation} - ${td.name}` : ''; + } + + public addTaskPrerequisite(event: Event): void { + event.stopPropagation(); + const taskDefinition = this.taskDefinition; + const selectedTaskPrerequisite = this.selectedTaskPrerequisite; + + this.selectedTaskPrerequisite = null; + + if (!taskDefinition) { + return this.alertService.error('Invalid task definition', 6000); + } + + if (!selectedTaskPrerequisite) { + return this.alertService.error( + 'Please select a task definition to add as a prerequisite', + 6000, + ); + } + + this.taskDefinitionService + .addTaskPrerequisite(taskDefinition, selectedTaskPrerequisite) + .subscribe({ + next: (response) => { + if (!response) { + this.alertService.error('Failed to add task prerequisite', 6000); + return; + } + taskDefinition.taskPrerequisitesCache.getOrCreate( + response.id, + this.taskPrerequisiteService, + response, + ); + this.mapPrerequisites(taskDefinition); + + this.alertService.success( + `Successfully added task ${selectedTaskPrerequisite.abbreviation} as a prerequisite`, + 5000, + ); + this.unit.refresh(); + this.filterTaskDefs(this.searchCtrl.value ?? ''); + }, + error: (error) => { + this.alertService.error(`Failed to add task prerequisite: ${error}`, 6000); + }, + }); + } + + public updateTaskPrerequisite(prerequisiteLink: TaskPrerequisite) { + this.taskDefinitionService + .updateTaskPrerequisite(prerequisiteLink, prerequisiteLink.taskStatus) + .subscribe({ + next: (response) => { + if (!response) { + this.alertService.error('Failed to update task prerequisite', 6000); + return; + } + this.alertService.success( + `Successfully updated prerequisite ${prerequisiteLink.prerequisite.abbreviation} to ${prerequisiteLink.taskStatus} `, + 5000, + ); + }, + error: (error) => { + this.alertService.error(`Failed to update task prerequisite: ${error}`, 6000); + }, + }); + } + + public removePrerequisite(prerequisiteToRemove: TaskPrerequisite) { + if (!prerequisiteToRemove) { + return; + } + prerequisiteToRemove.delete().subscribe(() => { + this.filterTaskDefs(this.searchCtrl.value ?? ''); + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html index 82ae176482..51bf4db54f 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html @@ -19,7 +19,7 @@ @if (taskDefinition.hasTaskResources) { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts index aa62abe87f..b7b2fa9564 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts @@ -71,7 +71,7 @@ export class TaskDefinitionResourcesComponent { public uploadTaskResources(files: FileList) { const validFiles = Array.from(files as ArrayLike).filter( - (f) => f.type === 'application/zip', + (f) => f.type === 'application/zip' || f.type === 'application/x-zip-compressed', ); if (validFiles.length > 0) { const file = validFiles[0]; @@ -83,7 +83,7 @@ export class TaskDefinitionResourcesComponent { error: (message) => this.alerts.error(message, 6000), }); } else { - this.alerts.error('Please drop a PDF to upload for this task', 6000); + this.alerts.error('Please drop a Zip to upload for this task', 6000); } } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html new file mode 100644 index 0000000000..fb02d119a2 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -0,0 +1,64 @@ +
    + + Enable test for task + + + @if (taskDefinition.scormEnabled) { + + @if (taskDefinition.hasScormData) { +
    + + + +
    + } + +
    +
    + + Allow students to review completed test attempt + + + Allow file upload regardless of test pass status + +
    + + Limit to this number of attempts - 0 is unlimited + + +
    + +
    + + Enable incremental time delays between test attempts + + If enabled, first 2 attempts can be completed immediately. Subsequently, a time delay will + be added, increasing by 2 hours every attempt made. +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts new file mode 100644 index 0000000000..8dee18a297 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts @@ -0,0 +1,67 @@ +import {Component, Input} from '@angular/core'; +import {FormControl, Validators} from '@angular/forms'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; + +@Component({ + selector: 'f-task-definition-scorm', + templateUrl: 'task-definition-scorm.component.html', + styleUrls: ['task-definition-scorm.component.scss'], +}) +export class TaskDefinitionScormComponent { + @Input() taskDefinition: TaskDefinition; + + constructor( + private fileDownloaderService: FileDownloaderService, + private alerts: AlertService, + private taskDefinitionService: TaskDefinitionService, + ) {} + + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + /** + * Open the SCORM test in a new tab - using preview mode. + */ + public previewScormTest() { + this.taskDefinition.previewScormTest(); + } + + public downloadScormData() { + this.fileDownloaderService.downloadFile( + this.taskDefinition.getScormDataUrl(true), + this.taskDefinition.name + '-SCORM.zip', + ); + } + + public removeScormData() { + this.taskDefinition.deleteScormData().subscribe({ + next: () => this.alerts.success('Deleted SCORM test data', 2000), + error: (message) => this.alerts.error(message, 6000), + }); + } + + public uploadScormData(files: FileList) { + // console.log(Array.from(files).map((f) => f.type)); + const validMimeTypes = ['application/zip', 'application/x-zip-compressed', 'multipart/x-zip']; + const validFiles = Array.from(files as ArrayLike).filter((f) => + validMimeTypes.includes(f.type), + ); + if (validFiles.length > 0) { + const file = validFiles[0]; + this.taskDefinitionService.uploadScormData(this.taskDefinition, file).subscribe({ + next: () => { + this.alerts.success('Uploaded SCORM test data', 2000); + this.taskDefinition.hasScormData = true; + }, + error: (message) => this.alerts.error(message, 6000), + }); + } else { + this.alerts.error('Please drop a zip file to upload SCORM test data for this task', 6000); + } + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index fe96cfb2df..28015f48b3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -25,12 +25,12 @@

    Check Similarity - @if (upreq.type === 'document') { -TurnItIn -} + @if (upreq.type === 'document' && tiiEnabled()) { + TurnItIn + } @if (upreq.type === 'code') { -Moss -} + Jplag + } Flag At @if (upreq.type === 'document' && upreq.tiiCheck) { - - -  % - -} + + +  % + + } -
    -@if (taskDefinition.needsMoss) { -
    - - Language used for Moss checks - - C - C# - C++ - Python - - - - Similarity percent to flag for Moss checks - - -
    +@if (taskDefinition.needsJplag) { +
    + + Language used for JPLAG checks + + Java + C + C++ + C# + Python + JavaScript + TypeScript + Go + Kotlin + R + Rust + Swift + Scala + LLVM IR + Scheme + EMF Metamodel + EMF Model + SCXML + Text + Multi-language + + + + Similarity percent to flag for JPLAG checks + + +
    +
    +
    + + Use Task Resources for JPlag Base Code +

    + Base code is a common framework included in all submissions. When enabled, student code + matching this base code will be ignored during JPlag similarity checks. The base code will + be automatically extracted from the task resources. +

    +
    +
    +
    } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index a8915d843b..a6d049446a 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/ import { MatTable, MatTableDataSource } from '@angular/material/table'; import { TaskDefinition, UploadRequirement } from 'src/app/api/models/task-definition'; import { Unit } from 'src/app/api/models/unit'; +import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'f-task-definition-upload', @@ -10,10 +11,12 @@ import { Unit } from 'src/app/api/models/unit'; }) export class TaskDefinitionUploadComponent { @Input() public taskDefinition: TaskDefinition; - @ViewChild('upreqTable', { static: true }) table: MatTable; + @ViewChild('upreqTable', {static: true}) table: MatTable; public columns: string[] = ['file-name', 'file-type', 'tii-check', 'flag-pct', 'row-actions']; + constructor(private constants: DoubtfireConstants) {} + public get unit(): Unit { return this.taskDefinition?.unit; } @@ -30,9 +33,13 @@ export class TaskDefinitionUploadComponent { this.table.renderRows(); } + public tiiEnabled(): boolean { + return this.constants.IsTiiEnabled.value; + } + public removeUpReq(upreq: UploadRequirement) { this.taskDefinition.uploadRequirements = this.taskDefinition.uploadRequirements.filter( - (anUpReq) => anUpReq.key != upreq.key + (anUpReq) => anUpReq.key != upreq.key, ); } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 814e814197..f36a92f380 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -13,7 +13,11 @@
    Tutorial Stream - Which tutor provides feedback? - + @for (stream of unit.tutorialStreams; track stream) { {{ stream.name }} } @@ -23,11 +27,38 @@ Related tutorials
      - @for (tutorial of taskDefinition.tutorialStream?.tutorialsIn(unit); track tutorial) { -
    • - {{ tutorial?.abbreviation }} {{ tutorial.tutor?.name }} -
    • -} + @for ( + tutorial of taskDefinition.tutorialStream?.tutorialsIn(unit) + | slice: 0 : (showAllTutorials ? undefined : 3); + track tutorial + ) { +
    • {{ tutorial?.abbreviation }} {{ tutorial.tutor?.name }}
    • + } + + @if (!showAllTutorials && taskDefinition.tutorialStream?.tutorialsIn(unit)?.length > 3) { +
    • + +{{ taskDefinition.tutorialStream.tutorialsIn(unit).length - 3 }} more tutorials +
    • + } + @if (taskDefinition.tutorialStream?.tutorialsIn(unit).length > 3) { +
      + @if (!showAllTutorials) { + + } @else { + + } +
      + }
    + +
    + Only allow tutors in this tutorial stream to assess this task +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts index 9732998592..53c87c7bf1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts @@ -10,7 +10,12 @@ import { Unit } from 'src/app/api/models/unit'; export class TaskDefinitionWhoComponent { @Input() taskDefinition: TaskDefinition; + showAllTutorials: boolean = false; public get unit(): Unit { return this.taskDefinition?.unit; } + + onTutorialStreamChange() { + this.showAllTutorials = false; + } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html index d346b1ce84..82562925c1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html @@ -1,163 +1,263 @@ -
    -
    -
    -
    -

    Task List

    -

    Plan the list of tasks for students to complete.

    +
    +
    +
    +

    Task List

    +

    Plan the list of tasks for students to complete.

    +
    +
    +
    + +
    + + +
    - -
    - - - +
    + +
    + + +
    +
    +
    + @if (unit.allowFlexibleDates) { + + } + +
    + + @if (unit.allowFlexibleDates) { + @if (manageDueDates) { +
    + +
    +
    +

    Manage Target Dates

    +

    Modify or add target dates for each target grade

    +
    +
    + + + + + + + + + + -
    Task + {{ td.abbreviation }} {{ td.name }} + +
    + +
    +
    +
    + + Start Date + + + + + + + Target Date + + @if (isStartAfterTarget(td, g)) { + Target date must be after start date + } + + + + +
    +
    + +
    +
    + } + } + +
    +
    - +
    + @if (selectedTaskDefinition) { + + } @else { +
    +

    Select a task definition

    +

    Pick a task from the left list to edit its details.

    +
    + } +
    +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.scss index 5996af349a..da9f77f5b0 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.scss +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.scss @@ -1,6 +1,16 @@ -.mat-toolbar { - background-color: white; - // position: fixed; - // bottom: 0; - // width: 100%; +::ng-deep input.mat-mdc-input-element.fallback-date { + font-style: italic; + color: #bfbfbf !important; + -webkit-text-fill-color: #bfbfbf !important; /* fixes some WebKit cases */ +} + +::ng-deep .date-error .mdc-notched-outline__leading, +::ng-deep .date-error .mdc-notched-outline__notch, +::ng-deep .date-error .mdc-notched-outline__trailing { + border-color: #ef4444 !important; // tailwind red-500 +} + +::ng-deep .date-error .mat-mdc-input-element { + color: #ef4444 !important; + -webkit-text-fill-color: #ef4444 !important; } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts index ee0f135c26..f40f563a7c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts @@ -1,13 +1,20 @@ -import { AfterViewInit, Component, Inject, Input, ViewChild } from '@angular/core'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { Subscription } from 'rxjs'; -import { confirmationModal, csvResultModalService, csvUploadModalService } from 'src/app/ajs-upgraded-providers'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, Inject, Input} from '@angular/core'; +import {MatTableDataSource} from '@angular/material/table'; +import {addWeeks} from 'date-fns'; +import {Subscription} from 'rxjs'; +import { + confirmationModal, + csvResultModalService, + csvUploadModalService, +} from 'src/app/ajs-upgraded-providers'; +import {Grade} from 'src/app/api/models/grade'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +type GradeCol = 'p' | 'c' | 'd' | 'hd'; @Component({ selector: 'f-unit-task-editor', @@ -15,40 +22,147 @@ import { AlertService } from 'src/app/common/services/alert.service'; styleUrls: ['unit-task-editor.component.scss'], }) export class UnitTaskEditorComponent implements AfterViewInit { - @ViewChild(MatTable, { static: false }) table: MatTable; - @ViewChild(MatSort, { static: false }) sort: MatSort; - @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; - @Input() unit: Unit; public taskDefinitionSource: MatTableDataSource; - public columns: string[] = ['name', 'grade', 'startDate', 'targetDate', 'deadlineDate', 'taskDefAction']; public filter: string; public selectedTaskDefinition: TaskDefinition; + public isTaskListCollapsed: boolean = false; + + public gradeColumns: string[] = ['p', 'c', 'd', 'hd']; + public dueDateColumns: string[] = ['taskDefinition', 'p', 'c', 'd', 'hd']; + public dueDateSource: MatTableDataSource; + + public manageDueDates: boolean; + + protected gradeNames: string[] = Grade.GRADES; + + isStartAfterTarget(td: TaskDefinition, g: GradeCol): boolean { + const start = this.getGradeStartDate(td, g); + const target = this.getGradeDueDate(td, g); + if (!start || !target) return false; + return new Date(start).getTime() > new Date(target).getTime(); + } + + getGradeStartDate(td: TaskDefinition, g: GradeCol): Date | null { + switch (g) { + case 'p': + return td.startDate ?? td.startDate; // fallback to existing startDate + case 'c': + return td.cStartDate ?? td.startDate; + case 'd': + return td.dStartDate ?? td.startDate; + case 'hd': + return td.hdStartDate ?? td.startDate; + } + } + + isFallbackStartDate(td: TaskDefinition, g: GradeCol): boolean { + switch (g) { + case 'p': + return false; // P is always real + case 'c': + return !td.cStartDate; + case 'd': + return !td.dStartDate; + case 'hd': + return !td.hdStartDate; + } + } + + setGradeStartDate(td: TaskDefinition, g: GradeCol, value: Date | null): void { + switch (g) { + case 'p': + td.startDate = value; + break; + case 'c': + td.cStartDate = value; + break; + case 'd': + td.dStartDate = value; + break; + case 'hd': + td.hdStartDate = value; + break; + } + + this.saveTaskDefinition(td); + } + + getGradeDueDate(td: TaskDefinition, g: GradeCol): Date | null { + switch (g) { + case 'p': + // return td.pTargetDate ?? td.dueDate ?? null; // fallback to existing dueDate + return td.targetDate ?? td.targetDate; // fallback to existing targetDate + case 'c': + return td.cTargetDate ?? td.targetDate; + case 'd': + return td.dTargetDate ?? td.targetDate; + case 'hd': + return td.hdTargetDate ?? td.targetDate; + } + } + + isFallbackTargetDate(td: TaskDefinition, g: GradeCol): boolean { + switch (g) { + case 'p': + return false; // P is always real + case 'c': + return !td.cTargetDate; + case 'd': + return !td.dTargetDate; + case 'hd': + return !td.hdTargetDate; + } + } + + setGradeDueDate(td: TaskDefinition, g: GradeCol, value: Date | null): void { + switch (g) { + case 'p': + td.targetDate = value; + break; + case 'c': + td.cTargetDate = value; + break; + case 'd': + td.dTargetDate = value; + break; + case 'hd': + td.hdTargetDate = value; + break; + } + + this.saveTaskDefinition(td); + } constructor( private taskDefinitionService: TaskDefinitionService, + private feedbackTemplateService: FeedbackTemplateService, private alerts: AlertService, @Inject(csvResultModalService) private csvResultModalService: any, @Inject(csvUploadModalService) private csvUploadModal: any, - @Inject(confirmationModal) private confirmationModal: any + @Inject(confirmationModal) private confirmationModal: any, ) {} ngAfterViewInit(): void { this.subscriptions.push( this.unit.taskDefinitionCache.values.subscribe((taskDefinitions) => { this.taskDefinitionSource = new MatTableDataSource(taskDefinitions); - this.taskDefinitionSource.paginator = this.paginator; - this.taskDefinitionSource.sort = this.sort; - this.taskDefinitionSource.filterPredicate = (data: any, filter: string) => data.matches(filter); - }) + this.taskDefinitionSource.filterPredicate = (data: any, filter: string) => + data.matches(filter); + }), ); } public saveTaskDefinition(taskDefinition: TaskDefinition) { - taskDefinition.save().subscribe(() => { - this.alerts.success('Task Saved'); - taskDefinition.setOriginalSaveData(this.taskDefinitionService.mapping); + taskDefinition.save().subscribe({ + next: () => { + this.alerts.success('Task Saved'); + taskDefinition.setOriginalSaveData(this.taskDefinitionService.mapping); + }, + error: (error) => { + this.alerts.error(`Failed to update task: ${error}`, 6000); + }, }); } @@ -59,56 +173,37 @@ export class UnitTaskEditorComponent implements AfterViewInit { public selectTaskDefinition(taskDefinition: TaskDefinition) { if (this.selectedTaskDefinition === taskDefinition) { - this.selectedTaskDefinition = null; - } else { - this.selectedTaskDefinition = taskDefinition; - - // Record original save data if none present - if (!this.selectedTaskDefinition.hasOriginalSaveData) { - this.selectedTaskDefinition.setOriginalSaveData(this.taskDefinitionService.mapping); - } + return; } - } - public sortData(sort: Sort) { - const data = this.taskDefinitionSource.data; + this.selectedTaskDefinition = taskDefinition; - if (!sort.active || sort.direction === '') { - this.taskDefinitionSource.data = data; - return; + // Record original save data if none present + if (!this.selectedTaskDefinition.hasOriginalSaveData) { + this.selectedTaskDefinition.setOriginalSaveData(this.taskDefinitionService.mapping); } - this.taskDefinitionSource.data = data.sort((a, b) => { - const isAsc = sort.direction === 'asc'; - switch (sort.active) { - case 'name': - return this.compare(a.abbreviation, b.abbreviation, isAsc); - case 'grade': - return this.compare(a.targetGrade, b.targetGrade, isAsc); - case 'startDate': - return this.compare(a.startDate.getTime(), b.startDate.getTime(), isAsc); - case 'targetDate': - return this.compare(a.targetDate.getTime(), b.targetDate.getTime(), isAsc); - case 'deadlineDate': - return this.compare(a.dueDate.getTime(), b.dueDate.getTime(), isAsc); - default: - return 0; - } - }); + this.feedbackTemplateService + .query({contextType: 'task_definitions', contextId: this.selectedTaskDefinition.id}, {}) + .subscribe({ + error: () => this.alerts.error('Error loading task feedback templates.'), + }); + } + + public isSelectedTaskDefinition(taskDefinition: TaskDefinition): boolean { + return this.selectedTaskDefinition === taskDefinition; } - public compare(a: number | string, b: number | string, isAsc: boolean): number { - return (a < b ? -1 : 1) * (isAsc ? 1 : -1); + public toggleTaskListCollapsed(): void { + this.isTaskListCollapsed = !this.isTaskListCollapsed; } applyFilter(filterValue: string) { + if (!this.taskDefinitionSource) return; + this.taskDefinitionSource.filter = filterValue.trim().toLowerCase(); this.selectedTaskDefinition = null; - - if (this.taskDefinitionSource.paginator) { - this.taskDefinitionSource.paginator.firstPage(); - } } private guessTaskAbbreviation() { @@ -137,9 +232,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { () => { this.unit.deleteTaskDefinition(taskDefinition); //TODO: reinstate ProgressModal.show "Deleting Task #{task.abbreviation}", 'Please wait while student projects are updated.', promise - - this.alerts.success('Task deleted'); - } + }, ); } @@ -147,7 +240,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { this.csvUploadModal.show( 'Upload Task Definitions as CSV', 'Test message', - { file: { name: 'Task Definition CSV Data', type: 'csv' } }, + {file: {name: 'Task Definition CSV Data', type: 'csv'}}, this.unit.getTaskDefinitionBatchUploadUrl(), (response: any) => { // at least one student? @@ -155,7 +248,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { if (response.success.length > 0) { this.unit.refresh(); } - } + }, ); } @@ -163,7 +256,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { this.csvUploadModal.show( 'Upload Task Sheets and Resources as Zip', 'Test message', - { file: { name: 'Task Sheets and Resources', type: 'zip' } }, + {file: {name: 'Task Sheets and Resources', type: 'zip'}}, this.unit.taskUploadUrl, (response: any) => { // at least one student? @@ -171,7 +264,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { if (response.success.length > 0) { this.unit.refresh(); } - } + }, ); } @@ -183,7 +276,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { task.abbreviation = abbr; task.description = 'New Description'; task.startDate = new Date(); - task.targetDate = new Date(); + task.targetDate = addWeeks(new Date(), 2); task.uploadRequirements = []; task.weighting = 4; task.targetGrade = 0; diff --git a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html index 7f24e23587..a11935e9d4 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html @@ -206,7 +206,7 @@

    Tutorials without a stream

    Capacity
    - {{ tutorial.capacity }} + {{ tutorial.numStudents }} / {{ tutorial.capacity }}
    @@ -225,13 +225,13 @@

    Tutorials without a stream

    -
    +
    -
    +
    @@ -246,7 +246,7 @@

    Tutorials without a stream

    -
    diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html index 6159d62f94..9f98162d6d 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html @@ -1,21 +1,30 @@
    - + @for (stream of unit.tutorialStreams; track stream) { - -} - + + } @empty { +
    +
    + groups +

    No Tutorials

    +

    + There are no tutorials yet. Create a tutorial stream to begin adding tutorials. +

    +
    +
    + } +
    + +
    + @for (activityType of activityTypes; track activityType) { - -} + + }
    diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.scss b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.scss index 95fde129f0..7f40e10c71 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.scss +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.scss @@ -1,5 +1,5 @@ -.new-activity-stream-button { - display: flex; - margin: 0 auto; - padding-left: 4px; +.no-tutorials .mat-icon { + font-size: 75px; + width: 75px; + height: 75px; } diff --git a/src/app/units/states/edit/edit.coffee b/src/app/units/states/edit/edit.coffee index 7951553c54..2a47b2c8b1 100644 --- a/src/app/units/states/edit/edit.coffee +++ b/src/app/units/states/edit/edit.coffee @@ -47,9 +47,6 @@ angular.module('doubtfire.units.states.edit', [ tasksTab: title: "Tasks" seq: 5 - taskAlignmentTab: - title: "Task Alignment" - seq: 5 groupsTab: title: "Groups" seq: 6 diff --git a/src/app/units/states/edit/edit.tpl.html b/src/app/units/states/edit/edit.tpl.html index 3ba73129a5..aae61b19f2 100644 --- a/src/app/units/states/edit/edit.tpl.html +++ b/src/app/units/states/edit/edit.tpl.html @@ -1,15 +1,14 @@ -
    +
    {{tab.title}} - - - + + + -
    diff --git a/src/app/units/states/index/index.coffee b/src/app/units/states/index/index.coffee index 7a7346a319..924196e301 100644 --- a/src/app/units/states/index/index.coffee +++ b/src/app/units/states/index/index.coffee @@ -17,7 +17,7 @@ angular.module('doubtfire.units.states.index', []) } ) -.controller("UnitsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newUnitService, newProjectService, listenerService, GlobalStateService, newUserService, alertService) -> +.controller("UnitsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newUnitService, newProjectService, listenerService, GlobalStateService, newUserService, FeedbackTemplateService) -> # Error - required unitId is missing! unitId = +$stateParams.unitId return $state.go('home') unless unitId @@ -39,6 +39,10 @@ angular.module('doubtfire.units.states.index', []) newProjectService.loadStudents(unit).subscribe({ next: (students)-> $scope.unit = unit + FeedbackTemplateService.query({contextType: 'units', contextId: unitId}).subscribe({ + error: (err) -> + alertService.error( "Error loading unit feedback templates: " + err, 8000) + }) error: (err)-> alertService.error( "Error loading students: " + err, 8000) setTimeout((()-> $state.go('home')), 5000) diff --git a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html new file mode 100644 index 0000000000..ccf3c460a1 --- /dev/null +++ b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html @@ -0,0 +1,83 @@ + + + + + + + + diff --git a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.scss b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.scss new file mode 100644 index 0000000000..0e78119808 --- /dev/null +++ b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.scss @@ -0,0 +1,13 @@ +mat-form-field { + padding: 1rem; +} + +li { + width: 100%; + margin-top: 1rem; + margin-bottom: 1rem; +} + +li button { + margin-right: 1rem; +} diff --git a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts new file mode 100644 index 0000000000..a5ea244d6b --- /dev/null +++ b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts @@ -0,0 +1,157 @@ +// +// Modal to show Doubtfire version info +// +import {HttpClient} from '@angular/common/http'; +import {Injectable, Component, Inject, OnInit} from '@angular/core'; +import {MatDialog, MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {D2lAssessmentMapping} from 'src/app/api/models/d2l/d2l_assessment_mapping'; +import {D2lAssessmentMappingService} from 'src/app/api/models/doubtfire-model'; +import {Unit} from 'src/app/api/models/unit'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; + +@Component({ + selector: 'f-d2l-transfer', + templateUrl: 'd2l-transfer.component.html', + styleUrl: 'd2l-transfer.component.scss', +}) +export class D2lTransferComponent implements OnInit { + public d2lDataMapping: D2lAssessmentMapping = new D2lAssessmentMapping(this.data); + private apiEndpoint: string; + private weightedUnit: boolean = false; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: Unit, + @Inject(MatDialogRef) + public dialogRef: MatDialogRef, + private alertService: AlertService, + public d2lAssessmentMappingService: D2lAssessmentMappingService, + public httpClient: HttpClient, + public doubtfireConstants: DoubtfireConstants, + public fileDownloader: FileDownloaderService, + ) {} + + public ngOnInit(): void { + this.data.loadD2lMapping().subscribe({ + next: (d2lDataMapping) => { + this.d2lDataMapping = d2lDataMapping; + + // If we have the org unit it, then we can check the grading standard + if (this.d2lDataMapping.orgUnitId) { + this.checkUnitGradesWeighted(); + } + }, + error: (_err) => { + // No mapping found, create a new one + this.d2lDataMapping = new D2lAssessmentMapping(this.data); + }, + }); + + this.httpClient.get(`${this.doubtfireConstants.API_URL}/d2l/endpoint`).subscribe({ + next: (response) => { + this.apiEndpoint = response; + }, + error: (err) => { + this.alertService.error(`Failed to get locaiton of D2L instance: ${err}`); + }, + }); + } + + public checkUnitGradesWeighted(): void { + this.httpClient + .get(`${this.doubtfireConstants.API_URL}/units/${this.data.id}/d2l/grades/weighted`) + .subscribe({ + next: (response) => { + this.weightedUnit = response; + }, + error: (err) => { + this.alertService.error(`Failed to get unit weighted status: ${err}`); + }, + }); + } + + public openD2l(): void { + const url = `${this.doubtfireConstants.API_URL}/d2l/login_url`; + this.httpClient.post(url, {}).subscribe({ + next: (response) => { + window.open(response, '_blank'); + }, + error: (err) => { + this.alertService.error(`Failed to get D2L login URL: ${err}`); + }, + }); + } + + public openWeightPage(): void { + const url = `${this.apiEndpoint}/d2l/lms/grades/admin/manage/item_props_newedit.d2l?objectId=${this.d2lDataMapping.gradeObjectId}&ou=${this.d2lDataMapping.orgUnitId}&scroll=weight`; + console.log(url); + window.open(url, '_blank'); + } + + public hasD2lMapping(): boolean { + return this.d2lDataMapping.id !== undefined; + } + + public hasWeight(): boolean { + return this.weightedUnit; + } + + public startTransfer(): void { + const url = `${this.doubtfireConstants.API_URL}/units/${this.data.id}/d2l/grades`; + this.httpClient.post(url, {}).subscribe({ + next: () => { + this.alertService.success('Transfer started'); + }, + error: (err) => { + this.alertService.error(`Failed to start transfer: ${err}`); + }, + }); + } + + public downloadRecord(): void { + this.httpClient + .get( + `${this.doubtfireConstants.API_URL}/units/${this.data.id}/d2l/grades/available`, + ) + .subscribe({ + next: (response) => { + if (response.running) { + this.alertService.error('Transfer in progress, please wait'); + } else if (response.available) { + const url = `${this.doubtfireConstants.API_URL}/units/${this.data.id}/d2l/grades`; + this.fileDownloader.downloadFile(url, `${this.data.code}-d2l-grades.csv`); + } else { + this.alertService.error( + 'No grade transfer results are available, and grade transfer does not appear to be in progress', + ); + } + }, + error: (err) => { + this.alertService.error(`Failed to download record: ${err}`); + }, + }); + } +} + +/** + * The about doubtfire modal service - used to create and show the modal + */ +// eslint-disable-next-line max-classes-per-file +@Injectable() +export class D2lTransferModal { + constructor(public dialog: MatDialog) {} + + public open(unit: Unit): void { + // Show dialog while the data above is being fetched + this.dialog.open(D2lTransferComponent, { + width: '600px', + data: unit, + }); + } +} + +interface GradesAvailableResponse { + available: boolean; + running: boolean; +} diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html new file mode 100644 index 0000000000..529708f97c --- /dev/null +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.scss b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts new file mode 100644 index 0000000000..eb3e1501bd --- /dev/null +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts @@ -0,0 +1,24 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Unit} from 'src/app/api/models/unit'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-download-staff-notes', + templateUrl: 'download-staff-notes.component.html', + styleUrl: 'download-staff-notes.component.scss', +}) +export class DownloadStaffNotesComponent implements OnInit { + @Input() unit: Unit; + + constructor(private alertService: AlertService) {} + + public ngOnInit(): void { + if (!this.unit) { + return console.error(`Invalid unit`); + } + } + + public downloadStaffNotesCsv() { + this.unit.downloadStaffNotesCsv(); + } +} diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee index ebbc09ec9b..62c70a04f3 100644 --- a/src/app/units/states/portfolios/portfolios.coffee +++ b/src/app/units/states/portfolios/portfolios.coffee @@ -14,11 +14,24 @@ angular.module('doubtfire.units.states.portfolios', []) roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] } ) -.controller("UnitPortfoliosStateCtrl", ($scope, alertService, analyticsService, gradeService, newProjectService, Visualisation, newTaskService, fileDownloaderService, newUserService) -> +.controller("UnitPortfoliosStateCtrl", ($scope, alertService, analyticsService, gradeService, newProjectService, Visualisation, newTaskService, fileDownloaderService, newUserService, D2lTransferModal, newUnitService, sidekiqProgressModalService) -> # TODO: (@alexcu) Break this down into smaller directives/substates + $scope.unit.loadD2lMapping().subscribe() + $scope.downloadGrades = -> fileDownloaderService.downloadFile($scope.unit.gradesUrl, "#{$scope.unit.code}-grades.csv") - $scope.downloadPortfolios = -> fileDownloaderService.downloadFile($scope.unit.portfoliosUrl, "#{$scope.unit.code}-portfolios.zip") + + $scope.downloadPortfolios = -> + newUnitService.zipPortfolios($scope.unit).subscribe({ + next: (newJob) -> + sidekiqProgressModalService.show("Downloading Portfolios: " + $scope.unit.code, newJob.id).subscribe({ + next: (job) -> + fileDownloaderService.downloadFile($scope.unit.portfoliosUrl, "#{$scope.unit.code}-portfolios.zip") + error: (message) -> alertService.error(message, 6000) + }) + error: (message) -> alertService.error(message, 6000) + }) + $scope.studentFilter = 'allStudents' $scope.portfolioFilter = 'withPortfolio' @@ -53,14 +66,18 @@ angular.module('doubtfire.units.states.portfolios', []) title: "View Progress" subtitle: "See the progress of the student" seq: 1 + viewStaffNotes: + title: "View Staff Notes" + subtitle: "See notes of the student add by staff" + seq: 2 viewPortfolio: title: "View Portfolio" subtitle: "See the portfolio of the student" - seq: 2 + seq: 3 assessPortfolio: title: "Assess Portfolio" subtitle: "Enter a grade for the student" - seq: 3 + seq: 4 $scope.setActiveTab($scope.tabs.selectStudent) @@ -121,7 +138,23 @@ angular.module('doubtfire.units.states.portfolios', []) $scope.selectedStudent = student $scope.project = null newProjectService.loadProject(student, $scope.unit).subscribe({ - next: (project) -> $scope.project = project + next: (project) -> + $scope.project = project + $scope.project.preloadedUrl = $scope.project.portfolioUrl() error: (message) -> alertService.error( message, 6000) }) + + $scope.hasD2lMapping = -> + $scope.unit.hasD2lMapping() + + $scope.transferToD2L = -> + D2lTransferModal.open($scope.unit) + + $scope.openProject = ($event, project) -> + $event.stopPropagation() + # HACK: avoids using window.open() to prevent AngularJS error + link = document.createElement('a') + link.href = "/projects/#{project.id}/dashboard/?tutor=true" + link.target = '_blank' + link.click() ) diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 51f09b077c..8625891202 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -1,4 +1,4 @@ -
    +
    Mark Portfolios >
    @@ -39,7 +43,11 @@

    Mark Portfolios

    -
    @@ -92,54 +100,93 @@

    Mark Portfolios

    No portfolios found

    - +
    + @@ -156,11 +203,12 @@

    Mark Portfolios

    + - + +
    - Student + Student + - Name + Name + - Tutor + Tutor + Tutorial - + - Target + Target + Submitted as - + + + + + Submission Date + - Stats + Stats - Portfolio? + Portfolio? + - Grade + Grade +
    {{student.tutorNames()}} {{student.shortTutorialDescription()}} - + - + {{student.portfolioSubmissionDate | date: 'EEE d MMM y, h:mm a'}} Mark Portfolios {{student.hasPortfolio ? "Yes" : "No"}} + {{student.hasPortfolio ? "Yes" : "No"}} + {{student.grade}} + +
    @@ -189,15 +246,22 @@

    Mark Portfolios

    rotate="false" >
    - - + + + +
    @@ -226,6 +290,18 @@

    Review Progress of {{selectedStudent.student.name}}

    +
    +
    +
    +

    Review Staff Notes for {{selectedStudent.student.name}}

    + View internal notes recorded by staff about the student. +
    +
    +
    + +
    +
    +
    @@ -237,7 +313,13 @@

    Review Portfolio of {{selectedStudent.student.name}}

    No Portfolio Submitted

    - +
    + + +
    diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html new file mode 100644 index 0000000000..c63db48f51 --- /dev/null +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.scss b/src/app/units/states/portfolios/upload-grades/upload-grades.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts new file mode 100644 index 0000000000..5d8e9a0020 --- /dev/null +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts @@ -0,0 +1,55 @@ +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {csvResultModalService, csvUploadModalService} from 'src/app/ajs-upgraded-providers'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {Unit} from 'src/app/api/models/unit'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-upload-grades', + templateUrl: 'upload-grades.component.html', + styleUrl: 'upload-grades.component.scss', +}) +export class UploadGradesComponent implements OnInit { + @Input() unit: Unit; + + constructor( + @Inject(csvUploadModalService) private csvUploadModal: any, + private sidekiqModalService: SidekiqProgressModalService, + @Inject(csvResultModalService) private csvResultModal: any, + private alertService: AlertService, + ) {} + + public ngOnInit(): void { + if (!this.unit) { + return console.error(`Invalid unit`); + } + } + + public uploadGradesCSV() { + this.csvUploadModal.show( + 'Upload Student Grades as CSV', + 'Import student grades', + { + file: {name: 'Feedback Templates CSV Data', type: 'csv'}, + }, + this.unit.gradesCSVUploadUrl, + (response: SidekiqJob) => { + if (!response) { + this.alertService.error('Failed to import grades', 6000); + return; + } + + this.sidekiqModalService.show('Import student grades', response.id).subscribe({ + next: (job) => { + this.csvResultModal.show('Student grade import results', JSON.parse(job.result)); + }, + error: (error) => { + console.error(error); + this.alertService.error('Failed to import grades', 6000); + }, + }); + }, + ); + } +} diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee index 07569a20a0..1542d89d20 100644 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee +++ b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee @@ -62,8 +62,8 @@ angular.module('doubtfire.units.states.rollover.directives.unit-dates-selector', } else body = { - start_date: $scope.saveData.startDate - end_date: $scope.saeData.endDate + start_date: $scope.saveData.startDate, + end_date: $scope.saveData.endDate } $scope.unit.rolloverTo(body).subscribe({ next: (response) -> diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html index 08d6a1a87d..fdfe7f5f21 100644 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html +++ b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html @@ -1,8 +1,8 @@
    -

    Create Unit

    - Duplicate an existing unit by specifying the time period. +

    Copy {{unit.code}} {{unit.nameAndPeriod}}

    + Duplicate this unit by copying it to the indicated teaching period, or a custom start and end date.
    @@ -39,11 +39,11 @@

    Create Unit

    - + -
    -
    -
    - - - - -
    - -
    - -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - - -
    -
    -

    - Click the button twice to reverse the sort ordering. -

    -
    - -
    -
    -

    No students found

    -

    - No students were found using the filters specified. -

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - - Username - - - - Name - - - - Stats - - - - Flags - - - - - Campus - - - - Tutorial - -
    - - - {{project.student.username || "N/A"}} - - {{project.student.name}} - - - - {{bar.value !== bar.value ? 'No Interaction' : (bar.value + '%')}} - - - - - - - - - - - - - - - - - - -
    - -
    -
    +
    +
    +
    +
    + + + + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    +

    + Click the button twice to reverse the sort ordering. +

    +
    +
    +
    +
    +

    No students found

    +

    + No students were found using the filters specified. +

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + Username + + + + Name + + + + Stats + + + + Flags + + + + + Campus + + + + Tutorial + +
    + + + {{project.student.username || "N/A"}} + + {{project.student.name}} + + + + {{bar.value !== bar.value ? 'No Interaction' : (bar.value + '%')}} + + + + + + + + + + + + + + + + + + +
    + +
    +
    diff --git a/src/app/units/states/tasks/definition/definition.coffee b/src/app/units/states/tasks/definition/definition.coffee index bd0bad8241..9dbdc249ea 100644 --- a/src/app/units/states/tasks/definition/definition.coffee +++ b/src/app/units/states/tasks/definition/definition.coffee @@ -22,6 +22,7 @@ angular.module('doubtfire.units.states.tasks.definition', [ .controller('TaskDefinitionStateCtrl', ($scope, newTaskService) -> $scope.taskData.source = newTaskService.queryTasksForTaskExplorer.bind(newTaskService) + $scope.viewType = 'explorer' $scope.taskData.taskDefMode = true $scope.showSearchOptions = true $scope.filters = { diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html new file mode 100644 index 0000000000..907c9793df --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html @@ -0,0 +1,43 @@ +

    +
    +
    + @if (action === 'show_less') { + thumb_up + } @else if (action === 'show_more') { + flag + } @else if (action === 'dismiss_ok') { + check_circle + } @else if (action === 'dismiss_good') { + task_alt + } @else if (action === 'overturn') { + gavel + } @else if (action === 'upheld') { + verified + } +
    +
    +
    {{ title }}
    + + Tutor: {{ task.tutor.user.name }} +
    +
    +

    + +

    + {{ description }} +

    + @if (showDismissAll) { +

    + + Apply this action to all {{ task.definition.abbreviation }} {{ task.definition.name }} tasks + from {{ task.tutor?.user.name ?? 'N/A' }}, currently waiting for moderation + +

    + } +
    + + + + diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.scss b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts new file mode 100644 index 0000000000..9b61056ad6 --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts @@ -0,0 +1,48 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {ConfirmModerationModalData} from './confirm-moderation-modal.service'; +import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {TaskService} from 'src/app/api/services/task.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {FeedbackModerationActionType} from 'src/app/api/models/task'; +import {Task} from 'src/app/api/models/task'; + +@Component({ + selector: 'f-confirm-moderation-modal', + templateUrl: './confirm-moderation-modal.component.html', + styleUrl: './confirm-moderation-modal.component.scss', +}) +export class ConfirmModerationModalComponent implements OnInit { + task: Task; + title: string; + description: string; + action: FeedbackModerationActionType; + showDismissAll: boolean; + callback: (applyToAll: boolean) => void; + + dismissAllTasks: boolean = false; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: ConfirmModerationModalData, + private alerts: AlertService, + private taskService: TaskService, + ) {} + + ngOnInit() { + this.task = this.data.task; + this.title = this.data.title; + this.description = this.data.description; + this.action = this.data.action; + this.showDismissAll = this.data.showDismissAll; + this.callback = this.data.callback; + } + + public runCallback() { + this.callback(this.dismissAllTasks); + this.dismiss(); + } + + public dismiss() { + this.dialogRef.close(); + } +} diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts new file mode 100644 index 0000000000..bd271f321c --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts @@ -0,0 +1,47 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {FeedbackModerationActionType} from 'src/app/api/models/task'; +import {ConfirmModerationModalComponent} from './confirm-moderation-modal.component'; +import {Task} from 'src/app/api/models/task'; + +export interface ConfirmModerationModalData { + task: Task; + title: string; + description: string; + action: FeedbackModerationActionType; + showDismissAll: boolean; + callback: (applyToAll: boolean) => void; +} + +@Injectable({ + providedIn: 'root', +}) +export class ConfirmModerationModalService { + constructor(public dialog: MatDialog) {} + + public show( + task: Task, + title: string, + description: string, + action: FeedbackModerationActionType, + showDismissAll: boolean, + callback: (applyToAll: boolean) => void, + ) { + const _dialogRef = this.dialog.open< + ConfirmModerationModalComponent, + ConfirmModerationModalData + >(ConfirmModerationModalComponent, { + data: { + task, + title, + description, + action, + showDismissAll, + callback, + }, + position: {top: '2.5%'}, + width: '100%', + maxWidth: '650px', + }); + } +} diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html new file mode 100644 index 0000000000..ccd8e468e1 --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html @@ -0,0 +1,75 @@ + + + @if (task.moderationType === 'random_sample' || task.moderationType === 'first_feedback') { + + + + + } @else if (task.moderationType === 'escalation') { + + + + } + diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.scss b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.scss new file mode 100644 index 0000000000..168ca35fb9 --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.scss @@ -0,0 +1,27 @@ +.center-buttons { + text-align: center; + + .button { + // margin: 0 6px; + transform: scale(0.8); + border-radius: 100%; + } + + .large-button { + transform: scale(1.15); + background-color: white; + } + + .large-button:hover { + background-color: #f5f5f5; + } + + .extra-large-button { + padding-top: 7px; + transform: scale(1.25); + } + + .extra-large-button:hover { + filter: brightness(0.85); + } +} diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts new file mode 100644 index 0000000000..945b0ae0d3 --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts @@ -0,0 +1,131 @@ +import {Component, Input} from '@angular/core'; +import {FeedbackModerationActionType, Task} from 'src/app/api/models/task'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {ConfirmModerationModalService} from './confirm-moderation-modal/confirm-moderation-modal.service'; +import {Router} from '@angular/router'; + +@Component({ + selector: 'f-moderation', + templateUrl: './moderation.component.html', + styleUrl: './moderation.component.scss', +}) +export class ModerationComponent { + @Input() task: Task; + + public moderated: Map = new Map(); + + constructor( + private alertService: AlertService, + private confirmModerationModal: ConfirmModerationModalService, + private router: Router, + ) {} + + overturn() { + this.confirmModerationModal.show( + this.task, + 'Overturn', + `The original feedback will be revised and the task outcome updated. + Provide clear, constructive feedback explaining the changes made, and record any guidance for the tutor in the tutor notes section.`, + 'overturn', + false, + () => { + this.moderateTask('overturn'); + }, + ); + } + + upheld() { + this.confirmModerationModal.show( + this.task, + 'Upheld', + `After reviewing the task and feedback, you are satisfied that the original marking and comments are appropriate and align with the assessment criteria. + No changes will be made. + Ensure any concerns raised by the student have been considered and addressed where necessary.`, + 'upheld', + false, + () => { + this.moderateTask('upheld'); + }, + ); + } + + showMore() { + this.confirmModerationModal.show( + this.task, + 'Show more from this tutor', + `There were concerns with feedback and you would like to see more tasks from this tutor. You will review this task again if further feedback is provided.`, + 'show_more', + false, + () => { + this.moderateTask('show_more'); + }, + ); + } + + showLess() { + this.confirmModerationModal.show( + this.task, + 'Show less from this tutor', + `The feedback provided by the tutor is satisfactory and you would like to see less of their feedback for moderation. You won't see this task again.`, + 'show_less', + true, + (applyToAll) => { + this.moderateTask('show_less', applyToAll); + }, + ); + } + + dismiss() { + this.confirmModerationModal.show( + this.task, + 'Dismiss from moderation', + 'This task will be removed from moderation and will not get a follow up. This will not affect how many tasks from this tutor are selected for moderation.', + 'dismiss_ok', + true, + (applyToAll) => { + this.moderateTask('dismiss_ok', applyToAll); + }, + ); + } + + snooze() { + this.confirmModerationModal.show( + this.task, + 'Snooze task', + 'This task will be hidden from moderation until the tutor leaves new feedback. This will not affect how many tasks from this tutor are selected for moderation.', + 'snooze', + false, + (applyToAll) => { + this.moderateTask('snooze', applyToAll); + }, + ); + } + + private moderateTask(action: FeedbackModerationActionType, applyToAll: boolean = false) { + this.task.moderateFeedback(action, applyToAll).subscribe({ + next: (_response) => { + if (applyToAll) { + this.alertService.success( + `Tasks moderated successfully. Refresh the list to view the updated queue.`, + 6000, + ); + } else { + this.alertService.success(`Task moderated successfully`, 2000); + } + + this.setModerated(this.task); + }, + error: (error) => { + this.alertService.error(`Failed to moderate task: ${error}`, 6000); + }, + }); + } + + private setModerated(task: Task) { + this.moderated.set(task, true); + } + + public isModerated(task: Task): boolean { + return this.moderated.get(task); + } +} diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html index bb9c9ba8ce..5912585804 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html @@ -1,6 +1,9 @@ -
    +
    @if (collapsable) { - - } @if (!isTaskDefMode) { - - } @if (isTaskDefMode) { - + + } + @if (!isTaskDefMode) { + + } + @if (isTaskDefMode) { + } - +
    @@ -93,16 +106,20 @@ name="taskDefID" (selectionChange)="taskDefinitionIdChanged()" > - All Task Definitions + All Task Definitions @for (td of unit.taskDefinitionCache.values | async; track td) { - - {{ td.abbreviation + ' - ' + td.name }} - + + {{ td.abbreviation + ' - ' + td.name }} + } +
    +
    + + Tutors + + @for (g of tutorGroups; track g.label) { + + @for (t of g.options; track t.id) { + + {{ t.inboxDescription }} + + } + + } + + +
    @@ -140,14 +186,19 @@ - +
    -
    +
    @if (!isNarrow) { -
    - -
    +
    + +
    }
    @@ -170,44 +223,66 @@ @if (filteredTasks) { - - - - @if (task) { -
    + @if (filteredTasks.length) { +
    {{ filteredTasks.length }} Tasks
    + } + + -
    - - -
    -

    {{ task.project.student.name }}

    -
    - {{ task.definition.abbreviation }} - - {{ task.definition.name }} -
    - -
    - @if (task.hasGrade()) { -
    - {{ task.gradeDesc() }} -
    - } - - @if (!isTaskDefMode) { -
    - - - - - + + @if (!isTaskDefMode) { +
    + + + + + +
    + } +
    +
    - } -
    - -
    - } - + } + - - - + + + }
    diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts index 95b498af20..1d3c166609 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts @@ -31,6 +31,10 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {HotkeysService} from '@ngneat/hotkeys'; +import {Router} from '@angular/router'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {TasksByTutorPipe} from 'src/app/common/filters/tasks-by-tutor.pipe'; @Component({ selector: 'df-staff-task-list', @@ -44,7 +48,11 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { @Input() project: Project; @Input() taskData: { - source: (unit: Unit, taskDef: TaskDefinition | number) => Observable; + source: ( + unit: Unit, + taskDef: TaskDefinition | number, + fetchMyStudentsOnly?: boolean, + ) => Observable; selectedTask: Task; taskKey: string; onSelectedTaskChange: (task: Task) => void; @@ -58,14 +66,17 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { forceStream: boolean; studentName: string; tutorialIdSelected: any; + unitRoleIdSelected: number | string; taskDefinitionIdSelected: number | TaskDefinition; }; @Input() showSearchOptions = true; @Input() isNarrow: boolean; + @Input() viewType: 'inbox' | 'explorer' | 'moderation'; + userHasTutorials: boolean; - filteredTasks: any[] = null; + filteredTasks: Task[] = null; studentFilter: { id: number | string; @@ -75,7 +86,14 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { tutorial?: Tutorial; }[] = null; - tasks: any[] = null; + tutorGroups: { + label: string; + options: {id: string | number; inboxDescription: string | undefined}[]; + }[] = []; + + tasks: Task[] = null; + + // hasJplagReport: boolean = false; watchingTaskKey: any; @@ -85,6 +103,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { definedTasksPipe = new TasksOfTaskDefinitionPipe(); tasksInTutorialsPipe = new TasksInTutorialsPipe(); taskWithStudentNamePipe = new TasksForInboxSearchPipe(); + tasksByTutorPipe = new TasksByTutorPipe(); // Let's call having a source of tasksForDefinition plus having a task definition // auto-selected with the search options open task def mode -- i.e., the mode // for selecting tasks by task definitions @@ -100,6 +119,10 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { originalFilteredTasks: any[] = null; allowHover = true; + // Track if all tasks have already been fetched + // Avoids redundant API calls when changing tutorial filters + fetchedAllTasks: boolean = false; + constructor( private selectedTaskService: SelectedTaskService, private alertService: AlertService, @@ -107,6 +130,9 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { public dialog: MatDialog, private userService: UserService, private hotkeys: HotkeysService, + private router: Router, + private taskDefinitionService: TaskDefinitionService, + private sidekiqProgressModalService: SidekiqProgressModalService, ) {} ngOnChanges(changes: SimpleChanges): void { @@ -122,27 +148,28 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { this.refreshData(); } } + ngOnDestroy(): void { - this.hotkeys.removeShortcuts('meta.shift.arrowdown'); - this.hotkeys.removeShortcuts('meta.shift.arrowup'); + this.hotkeys.removeShortcuts('control.shift.arrowdown'); + this.hotkeys.removeShortcuts('control.shift.arrowup'); } ngOnInit(): void { const registeredHotkeys = this.hotkeys.getHotkeys().map((hotkey) => hotkey.keys); - if (!registeredHotkeys.includes('meta.shift.arrowdown')) { + if (!registeredHotkeys.includes('control.shift.arrowdown')) { this.hotkeys .addShortcut({ - keys: 'meta.shift.arrowdown', + keys: 'control.shift.arrowdown', description: 'Select next task', }) .subscribe(() => this.nextTask()); } - if (!registeredHotkeys.includes('meta.shift.arrowup')) { + if (!registeredHotkeys.includes('control.shift.arrowup')) { this.hotkeys .addShortcut({ - keys: 'meta.shift.arrowup', + keys: 'control.shift.arrowup', description: 'Select previous task', }) .subscribe(() => this.previousTask()); @@ -158,12 +185,26 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { this.userHasTutorials = this.unit.tutorialsForUserName(this.userService.currentUser.name)?.length > 0; + const staff = this.unit.staff.slice(); + + const byName = (a: UnitRole, b: UnitRole) => + (a.user?.name ?? '').localeCompare(b.user?.name ?? ''); + + const mentored = staff + .filter((ur) => ur.mentorId === this.unitRole.id) + .slice() + .sort(byName); + + const allTutors = staff.slice().sort(byName); + this.filters = Object.assign( { studentName: null, tutorialIdSelected: (this.unitRole.role === 'Tutor' || 'Convenor') && this.userHasTutorials ? 'mine' : 'all', tutorials: [], + unitRoleIdSelected: + mentored.length > 0 && this.viewType === 'moderation' ? 'mentoring_all' : 'all', taskDefinitionIdSelected: null, taskDefinition: null, forceStream: true, @@ -191,8 +232,34 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { }; }), ]; + this.tutorGroups = [ + ...(mentored.length > 0 + ? [ + { + label: 'My Tutors (Mentoring)', + options: [ + {id: 'mentoring_all', inboxDescription: 'Show All Mine'}, + ...mentored.map((ur) => ({ + id: ur.id, + inboxDescription: ur.user?.name, + })), + ], + }, + ] + : []), + { + label: 'All Tutors', + options: [ + {id: 'all', inboxDescription: 'Show All'}, + ...allTutors.map((ur) => ({ + id: ur.id, + inboxDescription: ur.user?.name, + })), + ], + }, + ]; - this.tutorialIdChanged(); + this.tutorialIdChanged(false); this.setTaskDefFromTaskKey(this.taskData.taskKey); @@ -208,22 +275,59 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { downloadSubmissionPdfs() { const taskDef = this.filters.taskDefinition; - this.fileDownloaderService.downloadFile( - `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ - this.unit.id - }/task_definitions/${taskDef.id}/student_pdfs`, - `${this.unit.code}-${taskDef.abbreviation}-pdfs.zip`, - ); + this.taskDefinitionService.zipSubmissionPdfs(taskDef).subscribe({ + next: (newJob) => { + this.sidekiqProgressModalService + .show(`Downloading submission pdfs for ${taskDef.abbreviation}`, newJob.id) + .subscribe({ + next: (job) => { + this.fileDownloaderService.downloadFile( + `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ + this.unit.id + }/task_definitions/${taskDef.id}/student_pdfs`, + `${this.unit.code}-${taskDef.abbreviation}-pdfs.zip`, + ); + }, + }); + }, + error: (error) => { + this.alertService.error(error, 6000); + }, + }); } - downloadSubmissions() { + downloadSubmissionFiles() { + const taskDef = this.filters.taskDefinition; + this.taskDefinitionService.zipSubmissionFiles(taskDef).subscribe({ + next: (newJob) => { + this.sidekiqProgressModalService + .show(`Downloading submission files for ${taskDef.abbreviation}`, newJob.id) + .subscribe({ + next: (job) => { + this.fileDownloaderService.downloadFile( + `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ + this.unit.id + }/task_definitions/${taskDef.id}/download_submissions`, + `${this.unit.code}-${taskDef.abbreviation}-submissions.zip`, + ); + }, + }); + }, + error: (error) => { + this.alertService.error(error, 6000); + }, + }); + } + + downloadJPLAGReport() { const taskDef = this.filters.taskDefinition; this.fileDownloaderService.downloadFile( - `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ - this.unit.id - }/task_definitions/${taskDef.id}/download_submissions`, - `${this.unit.code}-${taskDef.abbreviation}-submissions.zip`, + taskDef.getJplagReportUrl(), + `${this.unit.code}-${taskDef.abbreviation}-jplag-report.zip`, ); + + const url = this.router.serializeUrl(this.router.createUrlTree(['/jplag-report-viewer'])); + window.open(url, '_blank'); } openDialog() { @@ -245,6 +349,15 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { this.filters.forceStream, ); } + + if (this.filters.unitRoleIdSelected) { + filteredTasks = this.tasksByTutorPipe.transform( + this.unitRole, + filteredTasks, + this.filters.unitRoleIdSelected, + ); + } + filteredTasks = this.taskWithStudentNamePipe.transform(filteredTasks, this.filters.studentName); this.filteredTasks = filteredTasks; @@ -270,7 +383,16 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { selectEl.focus(); } - tutorialIdChanged(): void { + unitRoleIdChanged(attemptRefreshData: boolean = true): void { + this.applyFilters(); + + const isExplorerView = this.isTaskDefMode; + if (attemptRefreshData && !this.fetchedAllTasks && !isExplorerView) { + this.refreshData(); + } + } + + tutorialIdChanged(attemptRefreshData: boolean = true): void { const tutorialId = this.filters.tutorialIdSelected; const filterOption = this.studentFilter.find((f) => f.id === tutorialId); @@ -279,14 +401,21 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { if (tutorialId === 'mine') { this.filters.tutorials = this.unit.tutorialsForUserName(this.userService.currentUser.name); + this.filters.unitRoleIdSelected = 'all'; } else if (tutorialId === 'all') { // Ignore tutorials filter this.filters.tutorials = null; } else { this.filters.tutorials = [filterOption.tutorial]; + this.filters.unitRoleIdSelected = 'all'; } this.applyFilters(); + + const isExplorerView = this.isTaskDefMode; + if (attemptRefreshData && !this.fetchedAllTasks && !isExplorerView) { + this.refreshData(); + } } // Task definition options @@ -325,13 +454,19 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { // Callback to refresh data from the task source private refreshData() { + const fetchMyStudentsOnly = this.filters.tutorialIdSelected === 'mine'; + this.loading = true; // Tasks for feedback or tasks for task, depending on the data source - this.taskData.source(this.unit, this.filters?.taskDefinitionIdSelected).subscribe({ - next: (response) => { - this.tasks = response; - this.applyFilters(); - this.loading = false; + this.taskData + .source(this.unit, this.filters?.taskDefinitionIdSelected, fetchMyStudentsOnly) + .subscribe({ + next: (response) => { + this.tasks = response; + this.applyFilters(); + this.loading = false; + + this.fetchedAllTasks = !fetchMyStudentsOnly && !this.isTaskDefMode; // Load initial set task, either the one provided (by the URL) // then load actual task in now or the first task that applies @@ -363,7 +498,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { } private scrollToTaskInList(task) { - const taskEl = document.querySelector(`staff-task-list #${task.taskKeyToIdString()}`) as any; + const taskEl = document.querySelector(`#${task.taskKeyToIdString()}`) as any; if (!taskEl) { return; } @@ -385,6 +520,9 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { } nextTask(): void { + if (!this.filteredTasks) { + return; + } const currentTaskIndex = this.filteredTasks.findIndex((task) => this.isSelectedTask(task)); if (currentTaskIndex >= this.filteredTasks.length) { return; @@ -427,4 +565,26 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { togglePin(task: Task) { task.pinned ? task.unpin() : task.pin(); } + + getWarningIcon(task: Task): 'warning' | 'overflow' | null { + if (!task.submissionDate) return null; + if (task.status !== 'ready_for_feedback') { + return null; + } + + const now = Date.now(); + const submission = new Date(task.submissionDate).getTime(); + + const daysSinceSubmission = (now - submission) / (1000 * 60 * 60 * 24); + + if (daysSinceSubmission >= task.unit.feedbackOverflowThresholdDays) { + return 'overflow'; + } + + if (daysSinceSubmission >= task.unit.feedbackWarningThresholdDays) { + return 'warning'; + } + + return null; + } } diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html new file mode 100644 index 0000000000..e7477fa34f --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html @@ -0,0 +1,34 @@ +
    + +
    diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.scss b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts new file mode 100644 index 0000000000..43a0a6bd2c --- /dev/null +++ b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts @@ -0,0 +1,44 @@ +import {Component, Input} from '@angular/core'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {Task} from 'src/app/api/models/task'; +import {UnitRole} from 'src/app/api/models/unit-role'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-task-claim', + templateUrl: './task-claim.component.html', + styleUrl: './task-claim.component.scss', +}) +export class TaskClaimComponent { + @Input() selectedTask: Task; + + constructor( + private taskService: TaskService, + private alertService: AlertService, + private snackBar: MatSnackBar, + private userService: UserService, + ) {} + + public get currentUnitRole(): UnitRole | undefined { + const currentUser = this.userService.currentUser; + return this.selectedTask.unit.staff.find((ur) => ur.user.id === currentUser.id); + } + + claimTask(task: Task) { + this.taskService.claimTask(task).subscribe({ + next: (_response) => { + this.alertService.success(`Successfully claimed task`, 6000); + this.snackBar.open( + `Successfully claimed task. This task will be automatically unclaimed after 30 minutes of inactivity.`, + 'OK', + ); + task.claimedByUnitRoleId = this.currentUnitRole.id; + }, + error: (error) => { + this.alertService.error(`Failed to claim task ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/units/states/tasks/inbox/inbox.coffee b/src/app/units/states/tasks/inbox/inbox.coffee index 9f04950ca0..77afab0740 100644 --- a/src/app/units/states/tasks/inbox/inbox.coffee +++ b/src/app/units/states/tasks/inbox/inbox.coffee @@ -20,5 +20,6 @@ angular.module('doubtfire.units.states.tasks.inbox', []) .controller('TaskInboxStateCtrl', ($scope, newTaskService) -> $scope.taskData.source = newTaskService.queryTasksForTaskInbox.bind(newTaskService) + $scope.viewType = 'inbox' $scope.taskData.taskDefMode = false ) diff --git a/src/app/units/states/tasks/inbox/inbox.component.html b/src/app/units/states/tasks/inbox/inbox.component.html index 84edcabe13..ca024e39d3 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.html +++ b/src/app/units/states/tasks/inbox/inbox.component.html @@ -1,15 +1,17 @@ +@if (!isMobileView) {
    @if (taskData) { - + }
    @if (subs$ | async) { @@ -42,20 +44,21 @@
    - +
    - +} @else {
    @if (taskData) { - + }
    @@ -84,3 +87,4 @@

    {{ taskData?.selectedTask?.project.student.nickname }}

    +} diff --git a/src/app/units/states/tasks/inbox/inbox.component.ts b/src/app/units/states/tasks/inbox/inbox.component.ts index 41716a3e40..554222dd75 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.ts @@ -1,13 +1,5 @@ import {CdkDragEnd, CdkDragStart, CdkDragMove} from '@angular/cdk/drag-drop'; -import { - AfterViewInit, - Component, - ElementRef, - Input, - OnDestroy, - OnInit, - ViewChild, -} from '@angular/core'; +import {Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {MediaObserver} from 'ng-flex-layout'; import {UIRouter} from '@uirouter/angular'; import {auditTime, merge, Observable, of, Subject, tap, withLatestFrom} from 'rxjs'; @@ -19,28 +11,41 @@ import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-ta import {HotkeysService, HotkeysHelpComponent} from '@ngneat/hotkeys'; import {MatDialog} from '@angular/material/dialog'; import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Tutorial} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; @Component({ selector: 'f-inbox', templateUrl: './inbox.component.html', styleUrls: ['./inbox.component.scss'], }) -export class InboxComponent implements OnInit, AfterViewInit { +export class InboxComponent implements OnInit, OnDestroy { @Input() unit: Unit; @Input() unitRole: UnitRole; @Input() taskData: {selectedTask: Task; any}; - + @Input() filters: { + taskDefinition: TaskDefinition; + tutorials: Tutorial[]; + forceStream: boolean; + studentName: string; + tutorialIdSelected: any; + taskDefinitionIdSelected: number | TaskDefinition; + }; + @Input() showSearchOptions: boolean; @ViewChild('inboxpanel') inboxPanel: ElementRef; @ViewChild('commentspanel') commentspanel: ElementRef; + @Input() viewType: 'inbox' | 'explorer' | 'moderation'; + subs$: Observable; private inboxStartSize$ = new Subject(); private dragMove$ = new Subject<{event: CdkDragMove; div: HTMLDivElement}>(); private dragMoveAudited$; - protected filters; - protected showSearchOptions; + // protected filters; + // protected showSearchOptions; public taskSelected = false; @@ -50,6 +55,10 @@ export class InboxComponent implements OnInit, AfterViewInit { return this.inboxPanel?.nativeElement.getBoundingClientRect().width < 150; } + get isMobileView(): boolean { + return this.mediaObserver.isActive('lt-md'); + } + constructor( private hotkeys: HotkeysService, private selectedTask: SelectedTaskService, @@ -58,6 +67,7 @@ export class InboxComponent implements OnInit, AfterViewInit { private router: UIRouter, public dialog: MatDialog, private userService: UserService, + private constants: DoubtfireConstants, ) { this.selectedTask.currentPdfUrl$.subscribe((url) => { this.visiblePdfUrl = url; @@ -67,35 +77,57 @@ export class InboxComponent implements OnInit, AfterViewInit { this.taskSelected = task != null; }); } - ngAfterViewInit(): void { - console.log('ngAfterViewInit'); - const markers = ['Admin', 'Convenor', 'Tutor', 'Student']; - if (markers.includes(this.userService.currentUser?.role)) { + ngOnInit(): void { + const registeredHotkeys = this.hotkeys.getHotkeys().map((hotkey) => hotkey.keys); + + if (!registeredHotkeys.includes('shift.?')) { this.hotkeys.registerHelpModal(() => { const ref = this.dialog.open(HotkeysHelpComponent, { // width: '250px', }); - ref.componentInstance.title = 'Formatif Marking Shortcuts'; + ref.componentInstance.title = `${this.constants.ExternalName.value} Feedback Shortcuts`; ref.componentInstance.dismiss.subscribe(() => ref.close()); }); } - } - ngOnInit(): void { - // this.hotkeys - // .addShortcut({ - // keys: 'control.c', - // description: 'Mark selected task as complete', - // }) - // .subscribe(() => this.selectedTask.selectedTask?.updateTaskStatus('complete')); - - // this.hotkeys - // .addShortcut({ - // keys: 'control.f', - // description: 'Mark selected task as fix', - // }) - // .subscribe(() => this.selectedTask.selectedTask?.updateTaskStatus('fix_and_resubmit')); + if (!registeredHotkeys.includes('control.shift.f')) { + this.hotkeys + .addShortcut({ + keys: 'control.shift.f', + description: 'Mark selected task as fix', + }) + .subscribe(() => this.selectedTask.selectedTask?.updateTaskStatus('fix_and_resubmit')); + } + + if (!registeredHotkeys.includes('control.shift.c')) { + this.hotkeys + .addShortcut({ + keys: 'control.Shift.c', + description: 'Mark selected task as complete', + }) + .subscribe(() => { + const task = this.selectedTask.selectedTask; + if (!task) { + return; + } + + if (!task.canMarkComplete) { + return; + } + + task.updateTaskStatus('complete'); + }); + } + + if (!registeredHotkeys.includes('control.shift.d')) { + this.hotkeys + .addShortcut({ + keys: 'control.shift.d', + description: 'Mark selected task as discuss', + }) + .subscribe(() => this.selectedTask.selectedTask?.updateTaskStatus('discuss')); + } this.dragMoveAudited$ = this.dragMove$.pipe( withLatestFrom(this.inboxStartSize$), @@ -128,6 +160,13 @@ export class InboxComponent implements OnInit, AfterViewInit { window.dispatchEvent(new Event('resize')); } + ngOnDestroy(): void { + this.hotkeys.removeShortcuts('control.shift.d'); + this.hotkeys.removeShortcuts('control.shift.f'); + this.hotkeys.removeShortcuts('control.shift.c'); + this.hotkeys.removeShortcuts('shift.?'); + } + startedDragging(event: CdkDragStart, div: HTMLDivElement) { event.source.element.nativeElement.classList.add('hovering'); const w = div.getBoundingClientRect().width; diff --git a/src/app/units/states/tasks/inbox/inbox.tpl.html b/src/app/units/states/tasks/inbox/inbox.tpl.html index d77bb14cc2..9adb06b9ad 100644 --- a/src/app/units/states/tasks/inbox/inbox.tpl.html +++ b/src/app/units/states/tasks/inbox/inbox.tpl.html @@ -1 +1,10 @@ - + diff --git a/src/app/units/states/tasks/moderation/moderation.coffee b/src/app/units/states/tasks/moderation/moderation.coffee new file mode 100644 index 0000000000..4a483fd314 --- /dev/null +++ b/src/app/units/states/tasks/moderation/moderation.coffee @@ -0,0 +1,33 @@ +angular.module('doubtfire.units.states.tasks.moderation', [ +]) + +# +# Get tasks for mentor moderation +# +.config(($stateProvider) -> + $stateProvider.state 'units/tasks/moderation', { + parent: 'units/tasks' + url: '/moderation/{taskKey:any}' + # We can recycle the task inbox, switching the data source scope variable + templateUrl: "units/states/tasks/inbox/inbox.tpl.html" + controller: "TaskModerationStateCtrl" + params: + taskKey: dynamic: true + data: + task: "Task Moderation" + pageTitle: "_Home_" + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] + } +) + +.controller('TaskModerationStateCtrl', ($scope, newTaskService) -> + $scope.taskData.source = newTaskService.queryTasksForMentorModeration.bind(newTaskService) + $scope.viewType = 'moderation' + $scope.showSearchOptions = false + $scope.filters = { + tutorialIdSelected: 'all' + taskDefinition: null + taskDefinitionIdSelected: null + } + $scope.taskData.taskDefMode = false +) diff --git a/src/app/units/states/tasks/overflow/overflow.coffee b/src/app/units/states/tasks/overflow/overflow.coffee new file mode 100644 index 0000000000..08bec0792f --- /dev/null +++ b/src/app/units/states/tasks/overflow/overflow.coffee @@ -0,0 +1,33 @@ +angular.module('doubtfire.units.states.tasks.overflow', [ +]) + +# +# Get tasks for overflow marking +# +.config(($stateProvider) -> + $stateProvider.state 'units/tasks/overflow', { + parent: 'units/tasks' + url: '/overflow/{taskKey:any}' + # We can recycle the task inbox, switching the data source scope variable + templateUrl: "units/states/tasks/inbox/inbox.tpl.html" + controller: "TaskOverflowStateCtrl" + params: + taskKey: dynamic: true + data: + task: "Task Overflow" + pageTitle: "_Home_" + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] + } +) + +.controller('TaskOverflowStateCtrl', ($scope, newTaskService) -> + $scope.taskData.source = newTaskService.queryTasksForOverflow.bind(newTaskService) + $scope.viewType = 'overflow' + $scope.showSearchOptions = false + $scope.filters = { + tutorialIdSelected: 'all' + taskDefinition: null + taskDefinitionIdSelected: null + } + $scope.taskData.taskDefMode = false +) diff --git a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html index 845e7203a5..56e528f29e 100644 --- a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html +++ b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html @@ -36,5 +36,6 @@
    +
    diff --git a/src/app/units/states/tasks/tasks.coffee b/src/app/units/states/tasks/tasks.coffee deleted file mode 100644 index 141e0364c6..0000000000 --- a/src/app/units/states/tasks/tasks.coffee +++ /dev/null @@ -1,68 +0,0 @@ -angular.module('doubtfire.units.states.tasks', [ - 'doubtfire.units.states.tasks.inbox' - 'doubtfire.units.states.tasks.definition' - 'doubtfire.units.states.tasks.viewer' -]) - -# -# Teacher child state for units for task-related activites -# -.config(($stateProvider) -> - $stateProvider.state 'units/tasks', { - abstract: true - parent: 'units/index' - url: '/tasks' - controller: 'UnitsTasksStateCtrl' - template: '' - data: - pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] - } -) - -.controller('UnitsTasksStateCtrl', ($scope, $state, newTaskService, listenerService, $transition$) -> - # Cleanup - listeners = listenerService.listenTo($scope) - - # Task data wraps: - # * the URL task composite key (project username + task def abbreviation) sourced from the URL, - # * the task source used for the task inbox list, - # * the actual selectedTask reference - # * the callback for when a task is updated (accepts the new task) - $scope.taskData = { - taskKey: null - source: null - selectedTask: null - onSelectedTaskChange: (task) -> - taskKey = task?.taskKey() - $scope.taskData.taskKey = taskKey - setTaskKeyAsUrlParams(task) - } - - # Sets URL parameters for the task key - setTaskKeyAsUrlParams = (task) -> - # Change URL of new task without notify - $state.go($state.$current, {taskKey: task?.taskKeyToUrlString()}, {notify: false}) - - # Sets task key from URL parameters - setTaskKeyFromUrlParams = (taskKeyString) -> - # Propagate selected task change downward to search for actual task - # inside the task inbox list - $scope.taskData.taskKey = newTaskService.taskKeyFromString(taskKeyString) - - # Child states will use taskKey to notify what task has been - # selected by the child on first load. - taskKey = $transition$.params().taskKey - setTaskKeyFromUrlParams(taskKey) - - # Whenever the state is changed, we look at the taskKey in the URL params - # see if we can set it as an actual taskKey object - listeners.push $scope.$on '$stateChangeStart', ($event, toState, toParams, fromState, fromParams) -> - setTaskKeyFromUrlParams(toParams.taskKey) - # Use preventDefault to prevent destroying the child state's - # scope if they are the same states. Otherwise, if they are - # the same, we destroy the state's scope and recreate it again - # unnecessarily; doing so will cause a re-request in the task - # list which is not required. - $event.preventDefault() if fromState == toState && fromParams.unitId == toParams.unitId -) diff --git a/src/app/units/states/tasks/tasks.component.html b/src/app/units/states/tasks/tasks.component.html new file mode 100644 index 0000000000..5105d51131 --- /dev/null +++ b/src/app/units/states/tasks/tasks.component.html @@ -0,0 +1 @@ + diff --git a/src/app/units/states/tasks/tasks.component.scss b/src/app/units/states/tasks/tasks.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/tasks/tasks.component.ts b/src/app/units/states/tasks/tasks.component.ts new file mode 100644 index 0000000000..5d8490546e --- /dev/null +++ b/src/app/units/states/tasks/tasks.component.ts @@ -0,0 +1,85 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { StateService, TransitionService, Transition } from '@uirouter/angular'; +import { TaskService } from 'src/app/api/services/task.service'; + +@Component({ + selector: 'f-units-tasks-state', + templateUrl: 'tasks.component.html', + styleUrls: ['tasks.component.scss'], +}) +export class UnitsTasksStateComponent implements OnInit, OnDestroy { + taskData: { + taskKey: unknown; + source: unknown; + selectedTask: unknown; + taskDefMode: boolean; + onSelectedTaskChange: (task: unknown) => void; + }; + + private deregisterTransition: Function; + + constructor( + private stateService: StateService, + private transitionService: TransitionService, + private taskService: TaskService, + ) {} + + ngOnInit(): void { + this.taskData = { + taskKey: null, + source: null, + selectedTask: null, + taskDefMode: false, + onSelectedTaskChange: (task: unknown) => { + // Bug fix 4: cleaner taskKey assignment — only call taskKey() if task exists + this.taskData.taskKey = (task as {taskKey: () => unknown})?.taskKey() ?? null; + // Bug fix 3: avoid redundant $state.go — only navigate if task exists + if (task) { + this.setTaskKeyAsUrlParams(task); + } + }, + }; + + // Read initial taskKey from URL on load + // Bug fix 1: null-safe parsing — guard against missing params + const initialKey = this.stateService.params?.['taskKey']; + this.setTaskKeyFromUrlParams(initialKey); + + // Listen for state transitions to keep taskKey in sync + this.deregisterTransition = this.transitionService.onStart({to: 'units/tasks.**'}, (trans: Transition) => { + const toParams = trans.params('to'); + const fromState = trans.from(); + const toState = trans.to(); + const fromParams = trans.params('from'); + + // Bug fix 2: force taskKeyString to a string to avoid type mismatches + const taskKeyString = toParams['taskKey'] != null ? String(toParams['taskKey']) : null; + this.setTaskKeyFromUrlParams(taskKeyString); + + // Bug fix 5: safer preventDefault — also check that states are defined before comparing + if (fromState?.name && fromState.name === toState?.name && fromParams['unitId'] === toParams['unitId']) { + return false; + } + }); + } + + ngOnDestroy(): void { + if (this.deregisterTransition) { + this.deregisterTransition(); + } + } + + private setTaskKeyAsUrlParams(task: unknown): void { + this.stateService.go( + this.stateService.$current.name, + {taskKey: (task as {taskKeyToUrlString: () => string})?.taskKeyToUrlString()}, + {notify: false }, + ); + } + + private setTaskKeyFromUrlParams(taskKeyString: string | null): void { + if (taskKeyString) { + this.taskData.taskKey = this.taskService.taskKeyFromString(taskKeyString); + } + } +} diff --git a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html index 2ee4198b7c..5ca7a38d06 100644 --- a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html +++ b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html @@ -1,6 +1,18 @@
    - + + + Task Details + + {{ panelOpenState() ? 'Hide' : 'Show' }} task details + + + +
    diff --git a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts index 57ea0b7993..8940b75542 100644 --- a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts +++ b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, signal } from '@angular/core'; import { TaskDefinition } from 'src/app/api/models/task-definition'; import { Unit } from 'src/app/api/models/unit'; import { TasksViewerService } from '../../../tasks-viewer.service'; @@ -19,4 +19,6 @@ export class FTaskDetailsViewComponent implements OnInit { this.taskDef = taskDef; }); } + + public readonly panelOpenState = signal(false); } diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html index 1ca78334f0..e5175a16a0 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html +++ b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html @@ -37,7 +37,7 @@ >
    - +

    {{ task.name }}

    diff --git a/src/assets/images/institution-logo.png b/src/assets/images/institution-logo.png new file mode 100644 index 0000000000..b1d13c1071 Binary files /dev/null and b/src/assets/images/institution-logo.png differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000000..a874b1e6d0 Binary files /dev/null and b/src/assets/images/logo.png differ diff --git a/src/index.html b/src/index.html index 54fed2d067..af609f230c 100644 --- a/src/index.html +++ b/src/index.html @@ -1,6 +1,7 @@ +