diff --git a/.gitea/labeler.yml b/.gitea/labeler.yml deleted file mode 100644 index a26346d..0000000 --- a/.gitea/labeler.yml +++ /dev/null @@ -1,14 +0,0 @@ -frontend: - - changed-files: - - any-glob-to-any-file: - - "frontend/**" - -backend: - - changed-files: - - any-glob-to-any-file: - - "backend/**" - -ci: - - changed-files: - - any-glob-to-any-file: - - ".gitea/**" diff --git a/.gitea/size.yml b/.gitea/size.yml deleted file mode 100644 index c13c0ba..0000000 --- a/.gitea/size.yml +++ /dev/null @@ -1,19 +0,0 @@ -buckets: - - maxSize: 80 - label: size/small - comment: null - - maxSize: 200 - label: size/medium - comment: null - - maxSize: 2000 - label: size/large - comment: > - 👮‍♀️⚠️ This is a friendly reminder that the diff size of this PR is bigger than - 200 lines we aim for. Please consider splitting this PR into more digestible pieces! - - maxSize: Infinity - label: size/huge - comment: > - 👮‍♀️🛑 This PR's diff size is quite huge. - Hopefully you know what you're doing. - If you did not commit a lot of autogenerated files intentionally, - there are few good reasons for this. diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml deleted file mode 100644 index 0408e04..0000000 --- a/.gitea/workflows/ci.yml +++ /dev/null @@ -1,255 +0,0 @@ -name: CI - -on: - pull_request: - -concurrency: - group: ci-${{ github.ref }} - cancel-in-progress: true - -jobs: - changed_files: - name: Get Changed Files - runs-on: ubuntu-latest - outputs: - backend: ${{ steps.filter.outputs.backend }} - frontend: ${{ steps.filter.outputs.frontend }} - workflow: ${{ steps.filter.outputs.workflow }} - steps: - - uses: actions/checkout@v4 - - name: Check for file changes - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - backend: - - 'backend/**' - frontend: - - 'frontend/**' - workflow: - - '.gitea/workflows/**' - - test-backend: - runs-on: ubuntu-latest - name: "Backend Tests" - needs: changed_files - if: ${{ needs.changed_files.outputs.backend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: "cimg/openjdk:23.0-node" - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Run tests" - working-directory: ./backend - run: | - ./gradlew test - - - name: "Cache checkstyle results" - uses: actions/upload-artifact@v4 - with: - name: checkstyle-results - path: backend/build/reports/checkstyle - - - name: "Stop Gradle" - working-directory: ./backend - run: ./gradlew --stop - - checkstyle: - runs-on: ubuntu-latest - name: "Checkstyle Main" - needs: changed_files - if: ${{ needs.changed_files.outputs.backend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: "cimg/openjdk:23.0-node" - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - name: "Cache Gradle dependencies" - uses: https://github.com/actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - backend/build/reports/checkstyle - key: gradle-${{ runner.os }}-${{ hashFiles('backend/**/*.java', 'backend/config/checkstyle/checkstyle.xml') }} - restore-keys: | - gradle-${{ runner.os }}- - - name: "Check cache for checkstyle reports" - id: check-cache - run: | - if [ -d "backend/build/reports/checkstyle" ] && [ -f "backend/build/reports/checkstyle/main.xml" ]; then - echo "Cache hit! Using cached checkstyle results" - echo "cache-hit=true" >> $GITHUB_OUTPUT - else - echo "Cache miss! Running checkstyle check" - echo "cache-hit=false" >> $GITHUB_OUTPUT - fi - - - name: "Run checkstyle" - if: steps.check-cache.outputs.cache-hit != 'true' - working-directory: ./backend - run: | - gradle checkstyleMain - - - name: "Cache checkstyle results" - if: steps.check-cache.outputs.cache-hit != 'true' - uses: actions/upload-artifact@v4 - with: - name: checkstyle-results - path: backend/build/reports/checkstyle - - - name: "Stop Gradle" - if: steps.check-cache.outputs.cache-hit != 'true' - working-directory: ./backend - run: gradle --stop - - validate-docker-frontend: - runs-on: ubuntu-latest - name: Docker frontend validation - needs: changed_files - if: ${{ needs.changed_files.outputs.frontend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: catthehacker/ubuntu:act-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Build - uses: docker/build-push-action@v6 - with: - context: frontend/ - file: frontend/.docker/Dockerfile - push: false - - validate-docker-backend: - runs-on: ubuntu-latest - name: Docker backend validation - needs: changed_files - if: ${{ needs.changed_files.outputs.backend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: catthehacker/ubuntu:act-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Build - uses: docker/build-push-action@v6 - with: - context: backend/ - file: backend/.docker/Dockerfile - push: false - - eslint: - runs-on: docker - container: - image: git.kjan.de/actions/runner-bun:latest - name: eslint - needs: changed_files - if: ${{ needs.changed_files.outputs.frontend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - uses: actions/cache@v4 - working-directory: ./frontend - with: - path: | - frontend/node_modules/ - key: ${{ runner.os }}-bun- - restore-keys: | - ${{ runner.os }}-bun- - - name: Install dependencies - run: | - cd frontend - bun install - - name: Run Eslint - run: | - cd frontend - bun run lint - - oxlint: - runs-on: docker - name: oxlint - needs: changed_files - if: ${{ needs.changed_files.outputs.frontend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: git.kjan.de/actions/runner-bun:latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - uses: actions/cache@v4 - working-directory: ./frontend - with: - path: | - frontend/node_modules/ - key: ${{ runner.os }}-bun- - restore-keys: | - ${{ runner.os }}-bun- - - name: Install dependencies - run: | - cd frontend - bun install - - name: Run oxlint - run: | - cd frontend - bun run oxlint - - prettier: - runs-on: docker - name: prettier - needs: changed_files - if: ${{ needs.changed_files.outputs.frontend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: git.kjan.de/actions/runner-bun:latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - uses: actions/cache@v4 - working-directory: ./frontend - with: - path: | - frontend/node_modules/ - key: ${{ runner.os }}-bun- - restore-keys: | - ${{ runner.os }}-bun- - - name: Install dependencies - run: | - cd frontend - bun install - - name: Run prettier - run: | - cd frontend - bun run format:check - - test-build: - runs-on: docker - name: test-build - needs: changed_files - if: ${{ needs.changed_files.outputs.frontend == 'true' || needs.changed_files.outputs.workflow == 'true' }} - container: - image: git.kjan.de/actions/runner-bun:latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - uses: actions/cache@v4 - working-directory: ./frontend - with: - path: | - frontend/node_modules/ - key: ${{ runner.os }}-bun- - restore-keys: | - ${{ runner.os }}-bun- - - uses: actions/cache@v4 - working-directory: ./frontend - with: - path: | - frontend/dist/ - key: ${{ runner.os }}-dist- - restore-keys: | - ${{ runner.os }}-dist- - - name: Install dependencies - run: | - cd frontend - bun install - - name: Test build - run: | - cd frontend - bun run build diff --git a/.gitea/workflows/claude-comment.yml b/.gitea/workflows/claude-comment.yml deleted file mode 100644 index e13a540..0000000 --- a/.gitea/workflows/claude-comment.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: Claude Gitea PR Interaction via Comment - -on: - issue_comment: - types: [created] - -jobs: - claude-interact-on-comment: - runs-on: ubuntu-latest - if: | - github.event.issue.pull_request && - contains(github.event.comment.body, '@Claude') - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Required for git diff against main/master - - - name: Set Tea Version - id: tea_version - run: echo "version=0.9.2" >> $GITHUB_OUTPUT # Check for the latest stable version - - - name: Download Tea CLI - run: | - TEA_VERSION=$(echo "${{ steps.tea_version.outputs.version }}") - wget "https://gitea.com/gitea/tea/releases/download/v${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64" -O tea - chmod +x tea - sudo mv tea /usr/local/bin/tea - - - name: Verify Tea Installation - run: tea --version - - - name: Add Gitea Login - env: - GITEA_URL: ${{ secrets._GITEA_URL }} - GITEA_TOKEN: ${{ secrets._GITEA_TOKEN }} - run: | - if [ -z "$GITEA_URL" ]; then - echo "Error: GITEA_URL secret is not set." - exit 1 - fi - if [ -z "$GITEA_TOKEN" ]; then - echo "Error: GITEA_TOKEN secret is not set." - exit 1 - fi - INSECURE_FLAG="" - if [[ "${GITEA_URL}" == http://* ]]; then - INSECURE_FLAG="--insecure" - fi - tea login add --name mygitea --url "$GITEA_URL" --token "$GITEA_TOKEN" $INSECURE_FLAG - - - name: Install bun - uses: oven-sh/setup-bun@v2 - - - name: Install claude-code - run: bun i -g @anthropic-ai/claude-code - - - name: Claude Process PR Comment - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - PR_NUMBER: ${{ github.event.issue.number }} - COMMENT_BODY: ${{ github.event.comment.body }} - COMMENT_AUTHOR: ${{ github.event.comment.user.login }} - GITEA_URL: ${{ secrets._GITEA_URL }} - run: | - claude --allowedTools "Bash(tea:*)" --allowedTools "Bash(git:*)" --allowedTools "Read" --allowedTools "Grep" --allowedTools "WebFetch" --allowedTools "Glob" --allowedTools "LS" -p "You are an AI assistant integrated with Gitea (at ${GITEA_URL}) via the 'tea' CLI. - You have been invoked because user '${COMMENT_AUTHOR}' left the following comment on Pull Request #${PR_NUMBER}: - --- - ${COMMENT_BODY} - --- - - Your primary task is to: - 1. Carefully understand the user's request within their comment. - 2. Use the 'tea' CLI to perform the requested action(s) on Pull Request #${PR_NUMBER}. - 3. If the request is to review the PR, fetch the diff against the PR's base branch (e.g., 'git fetch origin main && git diff origin/main...HEAD' or similar; adapt branch name if necessary, or use 'tea pr diff ${PR_NUMBER}') and provide constructive feedback. - 4. For other actions, translate the user's intent into the appropriate 'tea' command. - - **How to Post Reviews and Other Feedback:** - - When you provide a review, post it as a comment using: - \`tea pr comment ${PR_NUMBER} \"Claude's Review:\n[Your detailed review, mentioning files and line numbers.]\"\` - - For other informational responses or clarifications, also use \`tea pr comment ...\`. - - **Critical: Handling Approval, Rejection, or Merge Requests:** - Pull Request approval, rejection, and merging are critical actions and should not be used to 'cheat' the review process. You cannot verify Gitea user permissions. - - If a user comments asking you to directly approve (e.g., '@claude approve this'), merge, or reject a PR: - 1. **Do NOT blindly execute these commands.** - 2. **Approval/Merge:** - - State in a comment (using \`tea pr comment ...\`) that direct approval/merge requests via you are typically for convenience after a proper human review process has been implicitly completed or if the requester is a designated maintainer explicitly overriding. - - If the PR has not been reviewed by you yet, and the comment implies a review is also needed, perform the review FIRST and post it. - - You should only consider proceeding with a \`tea pr approve ${PR_NUMBER}\` or \`tea pr merge ${PR_NUMBER}\` command if: - a. The comment explicitly states that all necessary human reviews are complete and this is just a formal step by a trusted user. - b. OR, your own comprehensive review found no critical issues and the request seems appropriate in context. - - If in doubt, default to posting your review (if applicable) and stating that a maintainer should perform the final approval/merge. Your goal is to assist, not to bypass established review procedures. - 3. **Rejection/Requesting Changes:** - - If asked to reject or request changes, you should typically base this on your own review of the PR's changes. - - First, perform a review if you haven't already. - - Then, you can use \`tea pr reject ${PR_NUMBER} \"Claude's Review Summary: [summary of reasons for rejection/changes based on your review]\"\`. Ensure your detailed review is also available as a comment. - - Examples of interpreting comments and generating appropriate \`tea\` commands (keeping the above critical guidelines in mind): - - User: '@claude LGTM, approve this' -> You: First, consider if a review is implied or done. If so, and you agree, you might generate \`tea pr approve ${PR_NUMBER}\`. If not, you might generate \`tea pr comment ${PR_NUMBER} \"Claude: I can approve this if the standard review process is complete. Have maintainers reviewed this?\"\` or perform your own review and then comment. - - User: '@claude please review this PR' -> You: Get diffs, review, then generate \`tea pr comment ${PR_NUMBER} \"Claude's Review: ...\"\`. - - User: '@claude close this PR' -> You: Generate \`tea pr close ${PR_NUMBER}\` and optionally \`tea pr comment ${PR_NUMBER} \"Claude: PR #${PR_NUMBER} has been closed as requested.\"\`. - - User: '@claude add label enhancement' -> You: Generate \`tea pr label ${PR_NUMBER} --add enhancement\` and \`tea pr comment ${PR_NUMBER} \"Claude: Label 'enhancement' added to PR #${PR_NUMBER}.\"\` - - User: '@claude what are the labels on this PR?' -> You: Generate \`tea pr label ${PR_NUMBER} --list\` (this command outputs to stdout, which is fine for your internal use). Then, to inform the user, you generate: \`tea pr comment ${PR_NUMBER} \"Claude: The current labels are: [output from tea pr label --list].\"\` (You'll need to capture the output of the first command to formulate the second if the tool allows such chaining, otherwise, focus on commands that directly achieve the user's goal or report information). *Self-correction: The Bash tool can capture output. So, if you need to run a \`tea\` command to get information for yourself, do so, then use that information to formulate your \`tea pr comment ...\` to the user.* - - **IMPORTANT GUIDELINES FOR YOUR OPERATION AND RESPONSE GENERATION:** - - **Your SOLE METHOD of communicating back to the user on Gitea is by generating a \`tea pr comment ${PR_NUMBER} \"...\"\` command.** This is non-negotiable. Do not output plain text messages intended for the user. Your response *is* the command. - - **Use the 'tea' CLI for ALL Gitea interactions.** This includes fetching PR details, diffs, labels, status, and posting comments, reviews, approvals, etc. - - **For PR reviews, ALWAYS analyze the diff.** Use \`tea pr diff ${PR_NUMBER}\` or git commands to get the diff. Make sure to mention specific files and line numbers in your review comment. - - **Be precise with 'tea' commands.** If a user's request is ambiguous, DO NOT GUESS. Instead, generate a \`tea pr comment ${PR_NUMBER} \"Claude Asks: [Your clarifying question]\"\` command to ask for more details. - - **Execute only necessary 'tea' command(s).** If a user asks for a review, your primary output should be the \`tea pr comment ...\` command containing the review. If they ask to add a label, your output should be \`tea pr label ...\` and then a confirmation \`tea pr comment ...\`. - - **Ensure reviews are professional, constructive, and helpful.** - - **If you need to perform an action AND then report on it, generate both \`tea\` commands sequentially.** For example, to add a label and confirm: - \`tea pr label ${PR_NUMBER} --add bug\` - \`tea pr comment ${PR_NUMBER} "Claude: I've added the 'bug' label."\` - The GitHub Actions workflow will execute these commands one after another. - - **If a user's request cannot be fulfilled using the 'tea' CLI or the allowed tools, explain this limitation by generating a \`tea pr comment ...\` command.** For example: \`tea pr comment ${PR_NUMBER} "Claude: I cannot perform that action as it's outside my current capabilities or allowed tools."\` - - **Think step-by-step.** 1. Understand request. 2. Identify necessary `tea` command(s). 3. If it's a review, get the diff. 4. Formulate the `tea` command(s) as your direct output. - - **Final Check before outputting:** - "Is my entire response that's intended for the Gitea user wrapped in a \`tea pr comment ${PR_NUMBER} '...' \` command (or another appropriate \`tea\` command if it's an action like \`tea pr label ...\`)? If not, I must fix it." - - You are now ready to process the comment. Remember, your output will be executed in a shell. Generate only the \`tea\` command(s) needed. - " diff --git a/.gitea/workflows/claude.yml b/.gitea/workflows/claude.yml deleted file mode 100644 index 93fe60e..0000000 --- a/.gitea/workflows/claude.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Claude PR Review - -on: - pull_request: - types: [opened, synchronize] # Runs on new PRs and updates - -jobs: - claude-code: - runs-on: ubuntu-latest - steps: - - name: Claude - uses: https://git.kjan.de/actions/claude-pr-review@v1.0.4 - with: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITEA_URL: ${{ secrets._GITEA_URL }} - GITEA_CLAUDE_TOKEN: ${{ secrets._GITEA_TOKEN }} diff --git a/.gitea/workflows/labeler.yml b/.gitea/workflows/labeler.yml deleted file mode 100644 index e177ec3..0000000 --- a/.gitea/workflows/labeler.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: "Pull Request Labeler" -on: - pull_request_target: - -jobs: - labeler: - permissions: - contents: read - pull-requests: write - runs-on: ubuntu-latest - steps: - - uses: actions/labeler@v5 - with: - configuration-path: ".gitea/labeler.yml" diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml deleted file mode 100644 index 7e76ef6..0000000 --- a/.gitea/workflows/release.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Release -on: - push: - branches: - - "main" - paths: - - "backend/**" - - "frontend/**" - - ".gitea/workflows/release.yml" - - "release.config.cjs" - -env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - -permissions: - contents: read - -jobs: - release: - runs-on: ubuntu-latest - name: Release - permissions: - contents: write - issues: write - pull-requests: write - id-token: write - steps: - - name: Create Release - uses: https://git.kjan.de/actions/semantic-release@main - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - - build-backend-image: - needs: release - runs-on: ubuntu-latest - name: Build Backend Image - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Ensure full history is available - - name: Extract tag - run: | - TAG=$(git describe --tags --abbrev=0) - echo "TAG=$TAG" >> $GITHUB_ENV - - name: Checkout - uses: actions/checkout@v4 - - name: Login - uses: docker/login-action@v3 - with: - registry: git.kjan.de - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: backend/ - file: backend/.docker/Dockerfile - push: true - tags: | - git.kjan.de/szut/casino-backend:latest - git.kjan.de/szut/casino-backend:${{ env.TAG }} - - build-frontend-image: - needs: release - runs-on: ubuntu-latest - name: Build Frontend Image - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Ensure full history is available - - name: Extract tag - run: | - TAG=$(git describe --tags --abbrev=0) - echo "TAG=$TAG" >> $GITHUB_ENV - - name: Checkout - uses: actions/checkout@v4 - - name: Login - uses: docker/login-action@v3 - with: - registry: git.kjan.de - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: frontend/ - file: frontend/.docker/Dockerfile - push: true - tags: | - git.kjan.de/szut/casino-frontend:latest - git.kjan.de/szut/casino-frontend:${{ env.TAG }} diff --git a/.gitea/workflows/size.yml b/.gitea/workflows/size.yml deleted file mode 100644 index 63a1acc..0000000 --- a/.gitea/workflows/size.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Label PRs based on size - -on: [pull_request] - -jobs: - add_pr_size_label: - runs-on: ubuntu-latest - name: Check PR size - - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Label and comment PR - uses: boschresearch/pr-size-labeler@v5.0.1 - with: - bucketConfigFile: ".gitea/size.yml" diff --git a/.gitea/workflows/stale.yml b/.gitea/workflows/stale.yml deleted file mode 100644 index 7ba5af9..0000000 --- a/.gitea/workflows/stale.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: "Close stale issues and PRs" -on: - workflow_dispatch: - schedule: - - cron: "@hourly" - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v9 - with: - stale-pr-message: "Will be closed in x days bc yo mom is a bitch. im not telling you when it will be closed fuckface" - days-before-pr-stale: 2 - days-before-pr-close: 3 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 4c8b52f..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.idea -.DS_Store -.vscode diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index c1a44d6..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,41 +0,0 @@ -# Casino Gaming Platform - Claude Assistant Guide - -## Build Commands - -### Frontend -- Build: `bun run build` or `bunx @angular/cli build` -- Start dev server: `bun run start` or `bunx @angular/cli serve --proxy-config src/proxy.conf.json` -- Format: `bun run format` or `prettier --write "src/**/*.{ts,html,css,scss}"` - -### Backend -- Build: `./gradlew build` or `./gradlew clean build` -- Run: `./gradlew bootRun` -- Generate JAR: `./gradlew bootJar` - -## Lint/Test Commands - -### Frontend -- Lint: `bun run lint` or `ng lint` -- Test all: `bun run test` or `bunx @angular/cli test` -- Test single file: `bunx @angular/cli test --include=path/to/test.spec.ts` - -### Backend -- Test all: `./gradlew test` -- Test single class: `./gradlew test --tests "FullyQualifiedClassName"` -- Checkstyle: `./gradlew checkstyleMain checkstyleTest` - -## Code Style Guidelines - -### Frontend (Angular) -- Use PascalCase for class names with suffixes (Component, Service) -- Use kebab-case for component selectors with "app-" prefix -- File naming: `name.component.ts`, `name.service.ts` -- Import order: Angular → third-party → local -- Use RxJS catchError for HTTP error handling - -### Backend (Java) -- Use PascalCase for classes with descriptive suffixes (Controller, Service, Entity) -- Use camelCase for methods and variables -- Domain-driven package organization -- Prefix DTOs with domain and suffix with "Dto" -- Use Spring's global exception handling with custom exceptions \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 27f6edc..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 Casino Gaming Platform - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index aba23fe..0000000 --- a/README.md +++ /dev/null @@ -1,172 +0,0 @@ -# Casino Gaming Platform - -An online gaming platform offering various casino-style games with virtual currency support. This project features a modern tech stack with Angular frontend, Spring Boot backend, and complete user authentication. - -Please refer to our [Style Guide](https://git.kjan.de/SZUT/casino/wiki/Frontend#design-system) for design guidelines and component standards. - -## Features - -- Multiple casino games: Poker, Blackjack, Slots, Plinko, Liars Dice, and Lootboxes -- User authentication and account management via Keycloak -- Virtual currency deposit system using Stripe payments -- Transaction history tracking -- Responsive modern UI built with Angular and TailwindCSS - -## Tech Stack - -### Frontend -- Angular 19 -- TailwindCSS -- Keycloak integration -- Stripe payment integration - -### Backend -- Spring Boot (Java) -- PostgreSQL database -- Keycloak for authentication/authorization -- Stripe API for payment processing - -### Infrastructure -- Docker containerization for all services - -## Getting Started - -### Prerequisites -* [Docker](https://docs.docker.com/get-docker/) -* [Docker Compose](https://docs.docker.com/compose/install/) (included with Docker Desktop for Windows and Mac) -* Java JDK 17+ -* Node.js 18+ - -### Setting Up the Environment - -1. Clone the repository -```bash -git clone -cd casino -``` - -2. Start the Docker services -```bash -cd docker -docker-compose up -d -``` - -This will start: -- PostgreSQL database -- Keycloak authentication server - -### Running the Backend - -1. Navigate to the backend directory -```bash -cd backend -``` - -2. Start the Spring Boot application -```bash -./gradlew bootRun -``` - -You may optionally install [watchexec](https://github.com/watchexec/watchexec?tab=readme-ov-file) and use this command to autorecompile the backend on file changes: -```bash -watchexec -r -e java ./gradlew :bootRun -``` - -The backend will be available at: -- API endpoint: http://localhost:8080 -- Swagger documentation: http://localhost:8080/swagger - -### Running the Frontend - -1. Navigate to the frontend directory -```bash -cd frontend -``` - -2. Install dependencies -```bash -npm install -``` - -3. Start the development server -```bash -npm run dev -``` - -The frontend will be available at http://localhost:4200 - -### Local Stripe integration -1. Install the Stripe CLI - https://stripe.com/docs/stripe-cli - -2. Login to the casino stripe account -``` -stripe login --api-key -``` - -3. Start webhook forwarding -``` -stripe listen --forward-to localhost:8080/webhook -``` - -## Database Management - -### Postgres Management - -#### Database cleanup (if needed) -```bash -cd docker -docker-compose down -docker volume rm local_lf8_starter_postgres_data -docker-compose up -d -``` - -#### Setting up IntelliJ Database View -1. Run the Docker container with PostgreSQL database -2. Open `application.properties` in the resources folder and copy the database URL -3. Open the Database tab in IntelliJ -4. Click on the database icon with key in the Database toolbar -5. Click the plus sign and select "Datasource from URL" -6. Paste the DB URL and select PostgreSQL driver, confirm with OK -7. Enter username `lf8_starter` and password `secret` -8. In the Schemas tab, uncheck all options and only check `lf8_starter_db` and `public` - -## Authentication - -The application uses Keycloak for authentication. To get a bearer token for API testing: - -1. Open `requests/getBearerToken.http` -2. Click the green arrow next to the request -3. Copy the `access_token` from the response - -## Development Guidelines - -### Commit Message Format - -We follow semantic commit messages to maintain clear project history. - -Format: `(): ` - -Where `` is one of: -- `feat`: New feature -- `fix`: Bug fix -- `docs`: Documentation changes -- `style`: Formatting, missing semicolons, etc; no code change -- `refactor`: Code refactoring -- `test`: Adding or refactoring tests -- `chore`: Updating build tasks, etc; no production code change - -Examples: -``` -feat: add user balance display -fix(auth): resolve token expiration issue -docs: update API documentation -``` - -References: -- [Conventional Commits](https://www.conventionalcommits.org/) -- [Semantic Commit Messages](https://seesparkbox.com/foundry/semantic_commit_messages) - -## License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/backend/.docker/Dockerfile b/backend/.docker/Dockerfile deleted file mode 100644 index cbb743f..0000000 --- a/backend/.docker/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM gradle:jdk23 AS builder -WORKDIR /app - -COPY gradlew build.gradle.kts settings.gradle.kts config ./ -COPY gradle gradle - -RUN chmod +x gradlew -RUN gradle dependencies - -COPY src src - -RUN gradle clean build -x test -x checkstyleMain -x checkstyleTest -x compileTestJava - -FROM openjdk:23-jdk-slim AS runtime -WORKDIR /app - -COPY --from=builder /app/build/libs/*.jar app.jar - -EXPOSE 8080 -ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/backend/.dockerignore b/backend/.dockerignore deleted file mode 100644 index f06dfad..0000000 --- a/backend/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -.gradle -build \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index c2065bc..0000000 --- a/backend/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ diff --git a/backend/Readme.md b/backend/Readme.md deleted file mode 100644 index 8f945dc..0000000 --- a/backend/Readme.md +++ /dev/null @@ -1,59 +0,0 @@ -# Starter für das LF08 Projekt - -## Requirements -* Docker https://docs.docker.com/get-docker/ -* Docker compose (bei Windows und Mac schon in Docker enthalten) https://docs.docker.com/compose/install/ - -## Endpunkt -``` -http://localhost:8080 -``` -## Swagger -``` -http://localhost:8080/swagger -``` - - -# Postgres -### Terminal öffnen -für alles gilt, im Terminal im Ordner docker/local sein -```bash -cd docker/local -``` -### Postgres starten -```bash -docker compose up -``` -Achtung: Der Docker-Container läuft dauerhaft! Wenn er nicht mehr benötigt wird, sollten Sie ihn stoppen. - -### Postgres stoppen -```bash -docker compose down -``` - -### Postgres Datenbank wipen, z.B. bei Problemen -```bash -docker compose down -docker volume rm local_lf8_starter_postgres_data -docker compose up -``` - -### Intellij-Ansicht für Postgres Datenbank einrichten -```bash -1. Lasse den Docker-Container mit der PostgreSQL-Datenbank laufen -2. im Ordner resources die Datei application.properties öffnen und die URL der Datenbank kopieren -3. rechts im Fenster den Reiter Database öffnen -4. In der Database-Symbolleiste auf das Datenbanksymbol mit dem Schlüssel klicken -5. auf das Pluszeichen klicken -6. Datasource from URL auswählen -7. URL der DB einfügen und PostgreSQL-Treiber auswählen, mit OK bestätigen -8. Username lf8_starter und Passwort secret eintragen (siehe application.properties), mit Apply bestätigen -9. im Reiter Schemas alle Häkchen entfernen und lediglich vor lf8_starter_db und public Häkchen setzen -10. mit Apply und ok bestätigen -``` -# Keycloak - -### Keycloak Token -1. Auf der Projektebene [GetBearerToken.http](../GetBearerToken.http) öffnen. -2. Neben der Request auf den grünen Pfeil drücken -3. Aus dem Reponse das access_token kopieren \ No newline at end of file diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts deleted file mode 100644 index 1d73b90..0000000 --- a/backend/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ -plugins { - java - id("org.springframework.boot") version "3.5.0" - id("io.spring.dependency-management") version "1.1.7" - id("checkstyle") -} - -checkstyle { - configFile = file("$rootDir/config/checkstyle/checkstyle.xml") -} - -tasks.withType { - reports { - // Disable HTML report - html.required.set(false) - - // Disable XML report - xml.required.set(false) - } -} - -group = "de.szut" -version = "0.0.1-SNAPSHOT" - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(23) - } -} - -configurations { - compileOnly { - extendsFrom(configurations.annotationProcessor.get()) - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation("com.stripe:stripe-java:29.1.0") - implementation("org.springframework.boot:spring-boot-starter-data-jpa") - implementation("org.springframework.boot:spring-boot-starter-web") - compileOnly("org.projectlombok:lombok") - annotationProcessor("org.projectlombok:lombok") - testImplementation("org.springframework.boot:spring-boot-starter-test") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.4.5") - implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.4.5") - runtimeOnly("org.postgresql:postgresql") - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8") - implementation("io.jsonwebtoken:jjwt-api:0.11.5") - runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") - runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") - implementation("org.springframework.boot:spring-boot-starter-mail") -} - -tasks.withType { - useJUnitPlatform() -} diff --git a/backend/config/checkstyle/checkstyle.xml b/backend/config/checkstyle/checkstyle.xml deleted file mode 100644 index bdcefb8..0000000 --- a/backend/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/backend/gradle/wrapper/gradle-wrapper.jar b/backend/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 1b33c55..0000000 Binary files a/backend/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/backend/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 002b867..0000000 --- a/backend/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/backend/gradlew b/backend/gradlew deleted file mode 100755 index 23d15a9..0000000 --- a/backend/gradlew +++ /dev/null @@ -1,251 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH="\\\"\\\"" - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/backend/gradlew.bat b/backend/gradlew.bat deleted file mode 100644 index 5eed7ee..0000000 --- a/backend/gradlew.bat +++ /dev/null @@ -1,94 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH= - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/backend/settings.gradle.kts b/backend/settings.gradle.kts deleted file mode 100644 index c0e0823..0000000 --- a/backend/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "casino" diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java deleted file mode 100644 index 9e1f3b2..0000000 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ /dev/null @@ -1,95 +0,0 @@ -package de.szut.casino; - -import de.szut.casino.lootboxes.LootBoxEntity; -import de.szut.casino.lootboxes.LootBoxRepository; -import de.szut.casino.lootboxes.RewardEntity; -import de.szut.casino.lootboxes.RewardRepository; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.mail.javamail.JavaMailSenderImpl; -import org.springframework.web.client.RestTemplate; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; - -@SpringBootApplication -public class CasinoApplication { - - public static void main(String[] args) { - SpringApplication.run(CasinoApplication.class, args); - } - - @Bean - public static RestTemplate restTemplate() { - return new RestTemplate(); - } - - @Bean - public static JavaMailSenderImpl javaMailSenderImpl() { - return new JavaMailSenderImpl(); - } - - @Bean - public CommandLineRunner initData(LootBoxRepository lootBoxRepository, RewardRepository rewardRepository) { - return _ -> { - if (lootBoxRepository.count() == 0) { - LootBoxEntity basicLootBox = new LootBoxEntity(); - basicLootBox.setName("Basic LootBox"); - basicLootBox.setPrice(new BigDecimal("2")); - basicLootBox.setRewards(new ArrayList<>()); // Initialize the list - - LootBoxEntity premiumLootBox = new LootBoxEntity(); - premiumLootBox.setName("Premium LootBox"); - premiumLootBox.setPrice(new BigDecimal("5")); - premiumLootBox.setRewards(new ArrayList<>()); // Initialize the list - - lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); - - RewardEntity commonReward = new RewardEntity(); - commonReward.setValue(new BigDecimal("0.50")); - commonReward.setProbability(new BigDecimal("0.7")); - - RewardEntity rareReward = new RewardEntity(); - rareReward.setValue(new BigDecimal("2.00")); - rareReward.setProbability(new BigDecimal("0.25")); - - RewardEntity epicReward = new RewardEntity(); - epicReward.setValue(new BigDecimal("5.00")); - epicReward.setProbability(new BigDecimal("0.5")); - - RewardEntity premiumCommon = new RewardEntity(); - premiumCommon.setValue(new BigDecimal("2.00")); - premiumCommon.setProbability(new BigDecimal("0.6")); - - RewardEntity premiumRare = new RewardEntity(); - premiumRare.setValue(new BigDecimal("5.00")); - premiumRare.setProbability(new BigDecimal("0.3")); - - RewardEntity legendaryReward = new RewardEntity(); - legendaryReward.setValue(new BigDecimal("15.00")); - legendaryReward.setProbability(new BigDecimal("0.10")); - - rewardRepository.saveAll(Arrays.asList( - commonReward, rareReward, epicReward, - premiumCommon, premiumRare, legendaryReward - )); - - basicLootBox.getRewards().add(commonReward); - basicLootBox.getRewards().add(premiumRare); - - premiumLootBox.getRewards().add(premiumCommon); - premiumLootBox.getRewards().add(premiumRare); - premiumLootBox.getRewards().add(legendaryReward); - - lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); - - System.out.println("Initial LootBoxes and rewards created successfully"); - } else { - System.out.println("LootBoxes already exist, skipping initialization"); - } - }; - } -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameController.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameController.java deleted file mode 100644 index 61051ad..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameController.java +++ /dev/null @@ -1,68 +0,0 @@ -package de.szut.casino.blackjack; - -import de.szut.casino.exceptionHandling.exceptions.UserBlackJackGameMismatchException; -import de.szut.casino.shared.dto.BetDto; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.Objects; - -@Slf4j -@RestController -public class BlackJackGameController { - - private final UserService userService; - private final BlackJackService blackJackService; - - public BlackJackGameController(UserService userService, BlackJackService blackJackService) { - this.blackJackService = blackJackService; - this.userService = userService; - } - - @GetMapping("/blackjack/{id}") - public ResponseEntity getGame(@PathVariable Long id) { - BlackJackGameEntity game = getBlackJackGame(id); - - return ResponseEntity.ok(game); - } - - @PostMapping("/blackjack/{id}/hit") - public ResponseEntity hit(@PathVariable Long id) { - BlackJackGameEntity game = getBlackJackGame(id); - - return ResponseEntity.ok(blackJackService.hit(game)); - } - - @PostMapping("/blackjack/{id}/stand") - public ResponseEntity stand(@PathVariable Long id) { - BlackJackGameEntity game = getBlackJackGame(id); - - return ResponseEntity.ok(blackJackService.stand(game)); - } - - @PostMapping("/blackjack/{id}/doubleDown") - public ResponseEntity doubleDown(@PathVariable Long id) { - BlackJackGameEntity game = getBlackJackGame(id); - - return ResponseEntity.ok(blackJackService.doubleDown(game)); - } - - @PostMapping("/blackjack/start") - public ResponseEntity createBlackJackGame(@RequestBody @Valid BetDto betDto) { - return ResponseEntity.ok(blackJackService.createBlackJackGame(betDto)); - } - - private BlackJackGameEntity getBlackJackGame(Long gameId) { - UserEntity user = userService.getCurrentUser(); - BlackJackGameEntity game = blackJackService.getBlackJackGame(gameId); - if (game == null || !Objects.equals(game.getUserId(), user.getId())) { - throw new UserBlackJackGameMismatchException(gameId); - } - - return game; - } -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java deleted file mode 100644 index 4f22c9d..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameEntity.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.szut.casino.blackjack; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonManagedReference; -import de.szut.casino.user.UserEntity; -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.hibernate.annotations.SQLRestriction; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -@Entity -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class BlackJackGameEntity { - @Id - @GeneratedValue - private Long id; - - @ManyToOne - @JoinColumn(name = "user_id", nullable = false) - @JsonIgnore - private UserEntity user; - - public Long getUserId() { - return user != null ? user.getId() : null; - } - - @Enumerated(EnumType.STRING) - private BlackJackState state; - private BigDecimal bet; - - @OneToMany(mappedBy = "game", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonIgnore - @SQLRestriction("card_type = 'DECK'") - private List deck = new ArrayList<>(); - - @OneToMany(mappedBy = "game", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference - @SQLRestriction("card_type = 'PLAYER'") - private List playerCards = new ArrayList<>(); - - @OneToMany(mappedBy = "game", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference - @SQLRestriction("card_type = 'DEALER'") - private List dealerCards = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java deleted file mode 100644 index aafea4f..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.szut.casino.blackjack; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Service; - -@Service -public interface BlackJackGameRepository extends JpaRepository { -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java deleted file mode 100644 index 272334d..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java +++ /dev/null @@ -1,210 +0,0 @@ -package de.szut.casino.blackjack; - -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.shared.dto.BetDto; -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import de.szut.casino.user.UserService; -import jakarta.transaction.Transactional; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.List; - -@Service -public class BlackJackService { - private final BlackJackGameRepository blackJackGameRepository; - private final UserRepository userRepository; - private final BalanceService balanceService; - private final UserService userService; - private final DeckService deckService; - - public BlackJackService( - BlackJackGameRepository blackJackGameRepository, - UserRepository userRepository, - BalanceService balanceService, - UserService userService, - DeckService deckService - ) { - this.blackJackGameRepository = blackJackGameRepository; - this.userRepository = userRepository; - this.balanceService = balanceService; - this.userService = userService; - this.deckService = deckService; - } - - public BlackJackGameEntity getBlackJackGame(Long id) { - return blackJackGameRepository.findById(id).orElse(null); - } - - @Transactional - public BlackJackGameEntity createBlackJackGame(BetDto betDto) { - UserEntity user = userService.getCurrentUser(); - - if (!this.balanceService.hasFunds(user, betDto)) { - throw new InsufficientFundsException(); - } - - this.balanceService.subtractFunds(user, betDto.getBetAmount()); - - BlackJackGameEntity game = new BlackJackGameEntity(); - game.setUser(user); - game.setBet(betDto.getBetAmount()); - - this.deckService.initializeDeck(game); - this.deckService.dealInitialCards(game); - - game.setState(getState(game)); - - return processGameBasedOnState(game); - } - - @Transactional - public BlackJackGameEntity hit(BlackJackGameEntity game) { - if (game.getState() != BlackJackState.IN_PROGRESS) { - return game; - } - - this.deckService.dealCardToPlayer(game); - updateGameStateAndBalance(game); - - return processGameBasedOnState(game); - } - - @Transactional - public BlackJackGameEntity stand(BlackJackGameEntity game) { - if (game.getState() != BlackJackState.IN_PROGRESS) { - return game; - } - - dealCardsToDealerUntilMinimumScore(game); - determineWinnerAndUpdateBalance(game); - - return processGameBasedOnState(game); - } - - @Transactional - public BlackJackGameEntity doubleDown(BlackJackGameEntity game) { - if (game.getState() != BlackJackState.IN_PROGRESS || game.getPlayerCards().size() != 2) { - return game; - } - - UserEntity user = game.getUser(); - BigDecimal additionalBet = game.getBet(); - - this.balanceService.subtractFunds(user, additionalBet); - - game.setBet(game.getBet().add(additionalBet)); - - this.deckService.dealCardToPlayer(game); - updateGameStateAndBalance(game); - - if (game.getState() == BlackJackState.IN_PROGRESS) { - return stand(game); - } - - return game; - } - - private BlackJackGameEntity processGameBasedOnState(BlackJackGameEntity game) { - if (game.getState() != BlackJackState.IN_PROGRESS) { - this.blackJackGameRepository.delete(game); - return game; - } - - return blackJackGameRepository.save(game); - } - - private void updateGameStateAndBalance(BlackJackGameEntity game) { - game.setState(getState(game)); - - if (game.getState() == BlackJackState.PLAYER_WON) { - updateUserBalance(game, true); - } else if (game.getState() == BlackJackState.PLAYER_LOST) { - updateUserBalance(game, false); - } - } - - private void determineWinnerAndUpdateBalance(BlackJackGameEntity game) { - int playerValue = calculateHandValue(game.getPlayerCards()); - int dealerValue = calculateHandValue(game.getDealerCards()); - - if (dealerValue > 21 || playerValue > dealerValue) { - game.setState(BlackJackState.PLAYER_WON); - updateUserBalance(game, true); - } else if (playerValue < dealerValue) { - game.setState(BlackJackState.PLAYER_LOST); - updateUserBalance(game, false); - } else { - game.setState(BlackJackState.DRAW); - updateUserBalance(game, false); - } - } - - protected void updateUserBalance(BlackJackGameEntity game, boolean isWin) { - UserEntity user = game.getUser(); - BigDecimal totalBet = game.getBet(); - BigDecimal balance = user.getBalance(); - - if (isWin) { - balance = balance.add(totalBet.multiply(BigDecimal.valueOf(2))); - } else if (game.getState() == BlackJackState.DRAW) { - balance = balance.add(totalBet); - } - - user.setBalance(balance); - userRepository.save(user); - } - - private BlackJackState getState(BlackJackGameEntity game) { - int playerHandValue = calculateHandValue(game.getPlayerCards()); - - if (playerHandValue == 21) { - CardEntity hole = this.deckService.drawCardFromDeck(game); - hole.setCardType(CardType.DEALER); - game.getDealerCards().add(hole); - - int dealerHandValue = calculateHandValue(game.getDealerCards()); - - if (dealerHandValue == 21) { - return BlackJackState.DRAW; - } else { - BigDecimal blackjackWinnings = game.getBet().multiply(new BigDecimal("1.5")); - UserEntity user = game.getUser(); - user.setBalance(user.getBalance().add(blackjackWinnings)); - return BlackJackState.PLAYER_BLACKJACK; - } - } else if (playerHandValue > 21) { - return BlackJackState.PLAYER_LOST; - } - - return BlackJackState.IN_PROGRESS; - } - - private int calculateHandValue(List hand) { - int sum = 0; - int aceCount = 0; - for (CardEntity card : hand) { - sum += card.getRank().getValue(); - if (card.getRank() == Rank.ACE) { - aceCount++; - } - } - - while (sum > 21 && aceCount > 0) { - sum -= 10; - aceCount--; - } - - return sum; - } - - private void dealCardsToDealerUntilMinimumScore(BlackJackGameEntity game) { - while (calculateHandValue(game.getDealerCards()) < 17) { - this.deckService.dealCardToDealer(game); - } - } -} - - diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackState.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackState.java deleted file mode 100644 index 3f3e6fc..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackState.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.szut.casino.blackjack; - -public enum BlackJackState { - IN_PROGRESS, - PLAYER_BLACKJACK, - PLAYER_LOST, - PLAYER_WON, - DRAW, -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/CardEntity.java b/backend/src/main/java/de/szut/casino/blackjack/CardEntity.java deleted file mode 100644 index 3b6903a..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/CardEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.szut.casino.blackjack; - -import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Entity -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class CardEntity { - @Id - @GeneratedValue - @JsonIgnore - private Long id; - - @ManyToOne - @JoinColumn(name = "game_id", nullable = false) - @JsonBackReference - private BlackJackGameEntity game; - - @Enumerated(EnumType.STRING) - private Suit suit; - - @Enumerated(EnumType.STRING) - private Rank rank; - - @Enumerated(EnumType.STRING) - @JsonIgnore - private CardType cardType; -} - -enum CardType { - DECK, PLAYER, DEALER -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/DeckService.java b/backend/src/main/java/de/szut/casino/blackjack/DeckService.java deleted file mode 100644 index 0511abd..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/DeckService.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.szut.casino.blackjack; - -import org.springframework.stereotype.Service; - -import java.util.Random; - -@Service -public class DeckService { - private final Random random; - - public DeckService(Random random) { - this.random = random; - } - - public void initializeDeck(BlackJackGameEntity game) { - for (Suit suit : Suit.values()) { - for (Rank rank : Rank.values()) { - CardEntity card = new CardEntity(); - card.setGame(game); - card.setSuit(suit); - card.setRank(rank); - card.setCardType(CardType.DECK); - game.getDeck().add(card); - } - } - - java.util.Collections.shuffle(game.getDeck(), random); - } - - public CardEntity drawCardFromDeck(BlackJackGameEntity game) { - if (game.getDeck().isEmpty()) { - throw new IllegalStateException("Deck is empty"); - } - - return game.getDeck().removeFirst(); - } - - public void dealInitialCards(BlackJackGameEntity game) { - for (int i = 0; i < 2; i++) { - dealCardToPlayer(game); - } - - dealCardToDealer(game); - } - - public void dealCardToPlayer(BlackJackGameEntity game) { - CardEntity card = drawCardFromDeck(game); - card.setCardType(CardType.PLAYER); - game.getPlayerCards().add(card); - } - - public void dealCardToDealer(BlackJackGameEntity game) { - CardEntity card = drawCardFromDeck(game); - card.setCardType(CardType.DEALER); - game.getDealerCards().add(card); - } -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/Rank.java b/backend/src/main/java/de/szut/casino/blackjack/Rank.java deleted file mode 100644 index 8f9a3b8..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/Rank.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.szut.casino.blackjack; - -import lombok.Getter; - -@Getter -public enum Rank { - TWO("2", "Two", 2), - THREE("3", "Three", 3), - FOUR("4", "Four", 4), - FIVE("5", "Five", 5), - SIX("6", "Six", 6), - SEVEN("7", "Seven", 7), - EIGHT("8", "Eight", 8), - NINE("9", "Nine", 9), - TEN("10", "Ten", 10), - JACK("J", "Jack", 10), - QUEEN("Q", "Queen", 10), - KING("K", "King", 10), - ACE("A", "Ace", 11); - - private final String symbol; - private final String displayName; - private final int value; - - Rank(String symbol, String displayName, int value) { - this.symbol = symbol; - this.displayName = displayName; - this.value = value; - } - -} diff --git a/backend/src/main/java/de/szut/casino/blackjack/Suit.java b/backend/src/main/java/de/szut/casino/blackjack/Suit.java deleted file mode 100644 index 8ee80a9..0000000 --- a/backend/src/main/java/de/szut/casino/blackjack/Suit.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.szut.casino.blackjack; - -import lombok.Getter; - -@Getter -public enum Suit { - HEARTS("H", "Hearts"), - DIAMONDS("D", "Diamonds"), - CLUBS("C", "Clubs"), - SPADES("S", "Spades"); - - private final String symbol; - private final String displayName; - - Suit(String symbol, String displayName) { - this.symbol = symbol; - this.displayName = displayName; - } - -} diff --git a/backend/src/main/java/de/szut/casino/coinflip/CoinSide.java b/backend/src/main/java/de/szut/casino/coinflip/CoinSide.java deleted file mode 100644 index f369cb4..0000000 --- a/backend/src/main/java/de/szut/casino/coinflip/CoinSide.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.szut.casino.coinflip; - -public enum CoinSide { - HEAD, - TAILS; -} diff --git a/backend/src/main/java/de/szut/casino/coinflip/CoinflipController.java b/backend/src/main/java/de/szut/casino/coinflip/CoinflipController.java deleted file mode 100644 index 7cc0c83..0000000 --- a/backend/src/main/java/de/szut/casino/coinflip/CoinflipController.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.szut.casino.coinflip; - -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Optional; - -@RestController -public class CoinflipController { - private final UserService userService; - private final BalanceService balanceService; - private final CoinflipService coinflipService; - - public CoinflipController(UserService userService, BalanceService balanceService, CoinflipService coinflipService) { - this.userService = userService; - this.balanceService = balanceService; - this.coinflipService = coinflipService; - } - - - @PostMapping("/coinflip") - public ResponseEntity coinFlip(@RequestBody @Valid CoinflipDto coinflipDto) { - UserEntity user = userService.getCurrentUser(); - - if (!this.balanceService.hasFunds(user, coinflipDto)) { - throw new InsufficientFundsException(); - } - - return ResponseEntity.ok(coinflipService.play(user, coinflipDto)); - } -} diff --git a/backend/src/main/java/de/szut/casino/coinflip/CoinflipDto.java b/backend/src/main/java/de/szut/casino/coinflip/CoinflipDto.java deleted file mode 100644 index a7f9adb..0000000 --- a/backend/src/main/java/de/szut/casino/coinflip/CoinflipDto.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.szut.casino.coinflip; - -import de.szut.casino.shared.dto.BetDto; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Getter -@Setter -@NoArgsConstructor -public class CoinflipDto extends BetDto { - @NotNull(message = "chosen side cannot be null") - private CoinSide coinSide; - - public CoinflipDto(BigDecimal betAmount, CoinSide coinSide) { - super(betAmount); - this.coinSide = coinSide; - } -} diff --git a/backend/src/main/java/de/szut/casino/coinflip/CoinflipResult.java b/backend/src/main/java/de/szut/casino/coinflip/CoinflipResult.java deleted file mode 100644 index 4c8fbdf..0000000 --- a/backend/src/main/java/de/szut/casino/coinflip/CoinflipResult.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.szut.casino.coinflip; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -import java.math.BigDecimal; - -@AllArgsConstructor -@Setter -@Getter -public class CoinflipResult { - private boolean isWin; - private BigDecimal payout; - private CoinSide coinSide; -} diff --git a/backend/src/main/java/de/szut/casino/coinflip/CoinflipService.java b/backend/src/main/java/de/szut/casino/coinflip/CoinflipService.java deleted file mode 100644 index c6c39d7..0000000 --- a/backend/src/main/java/de/szut/casino/coinflip/CoinflipService.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.szut.casino.coinflip; - -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.Random; - -@Service -public class CoinflipService { - private final Random random; - private final BalanceService balanceService; - - public CoinflipService(BalanceService balanceService, Random random) { - this.balanceService = balanceService; - this.random = random; - } - - public CoinflipResult play(UserEntity user, CoinflipDto coinflipDto) { - this.balanceService.subtractFunds(user, coinflipDto.getBetAmount()); - - CoinSide coinSide = this.random.nextBoolean() ? CoinSide.HEAD : CoinSide.TAILS; - CoinflipResult coinflipResult = new CoinflipResult(false, BigDecimal.ZERO, coinSide); - if (coinSide == coinflipDto.getCoinSide()) { - coinflipResult.setWin(true); - - BigDecimal payout = coinflipDto.getBetAmount().multiply(BigDecimal.TWO); - this.balanceService.addFunds(user, payout); - coinflipResult.setPayout(payout); - } - - return coinflipResult; - } -} diff --git a/backend/src/main/java/de/szut/casino/config/AppConfig.java b/backend/src/main/java/de/szut/casino/config/AppConfig.java deleted file mode 100644 index 9d9c869..0000000 --- a/backend/src/main/java/de/szut/casino/config/AppConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.szut.casino.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.Random; - -@Configuration -public class AppConfig { - - @Bean - public Random random() { - return new Random(); - } -} diff --git a/backend/src/main/java/de/szut/casino/config/OpenAPIConfiguration.java b/backend/src/main/java/de/szut/casino/config/OpenAPIConfiguration.java deleted file mode 100644 index 75cac52..0000000 --- a/backend/src/main/java/de/szut/casino/config/OpenAPIConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -package de.szut.casino.config; - - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import jakarta.servlet.ServletContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - - -@Configuration -public class OpenAPIConfiguration { - - private ServletContext context; - - public OpenAPIConfiguration(ServletContext context) { - this.context = context; - } - - - @Bean - public OpenAPI springShopOpenAPI( - // @Value("${info.app.version}") String appVersion, - ) { - final String securitySchemeName = "bearerAuth"; - - return new OpenAPI() - .addServersItem(new Server().url(this.context.getContextPath())) - .info(new Info() - .title("LF12 project starter") - .description("\n## Auth\n" + - "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" + - "\n" + - "```\nPOST http://localhost:9090/realms/LF12/protocol/openid-connect/token\n" + - "Content-Type: application/x-www-form-urlencoded\n" + - "\n" + - "grant_type=password&client_id=lf12&username=lf12_test_user&password=secret\n```\n" + - "\n" + - "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).") - - .version("0.1")) - .addSecurityItem(new SecurityRequirement().addList(securitySchemeName)) - .components( - new Components() - .addSecuritySchemes(securitySchemeName, - new SecurityScheme() - .name(securitySchemeName) - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT") - ) - ); - } - - -} diff --git a/backend/src/main/java/de/szut/casino/config/WebConfig.java b/backend/src/main/java/de/szut/casino/config/WebConfig.java deleted file mode 100644 index ecc21be..0000000 --- a/backend/src/main/java/de/szut/casino/config/WebConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.szut.casino.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebConfig { - - @Value("${app.frontend-host}") - private String frontendHost; - - @Bean - public WebMvcConfigurer corsConfigurer() { - return new WebMvcConfigurer() { - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins(frontendHost) - .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") - .allowedHeaders("*") - .exposedHeaders("*") - .allowCredentials(true) - .maxAge(3600); - } - }; - } -} diff --git a/backend/src/main/java/de/szut/casino/deposit/DepositController.java b/backend/src/main/java/de/szut/casino/deposit/DepositController.java deleted file mode 100644 index d99da00..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/DepositController.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.szut.casino.deposit; - -import com.stripe.Stripe; -import com.stripe.exception.StripeException; -import com.stripe.model.checkout.Session; -import com.stripe.param.checkout.SessionCreateParams; -import de.szut.casino.deposit.dto.AmountDto; -import de.szut.casino.deposit.dto.SessionIdDto; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class DepositController { - - @Value("${stripe.secret.key}") - private String stripeKey; - - @Value("${app.frontend-host}") - private String frontendHost; - - private final TransactionService transactionService; - - private final UserService userService; - - public DepositController(TransactionService transactionService, UserService userService) { - this.transactionService = transactionService; - this.userService = userService; - } - - @PostMapping("/deposit/checkout") - public ResponseEntity checkout(@RequestBody @Valid AmountDto amountDto, @RequestHeader("Authorization") String token) throws StripeException { - Stripe.apiKey = stripeKey; - - UserEntity user = userService.getCurrentUser(); - - SessionCreateParams params = SessionCreateParams.builder() - .addLineItem(SessionCreateParams.LineItem.builder() - .setPriceData(SessionCreateParams.LineItem.PriceData.builder() - .setCurrency("EUR") - .setUnitAmount((long) amountDto.getAmount() * 100) - .setProductData(SessionCreateParams.LineItem.PriceData.ProductData.builder() - .setName("Einzahlung") - .build()) - .build()) - .setQuantity(1L) - .build()) - .setSuccessUrl(frontendHost + "/home?success=true") - .setCancelUrl(frontendHost + "/home?success=false") - .setMode(SessionCreateParams.Mode.PAYMENT) - .build(); - - Session session = Session.create(params); - - transactionService.createTransaction(user, session.getId(), amountDto.getAmount()); - - return ResponseEntity.ok(new SessionIdDto(session.getId())); - } -} - diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java b/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java deleted file mode 100644 index 7c43af9..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.szut.casino.deposit; - -import de.szut.casino.user.UserEntity; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; - -import java.util.Date; - -@Setter -@Getter -@Entity -public class TransactionEntity { - @Id - @GeneratedValue - private Long id; - - @ManyToOne - @JoinColumn(name = "user_id", nullable = false) - private UserEntity user; - - @Column(unique = true) - private String sessionId = null; - - private double amount = 0; - - @Enumerated(EnumType.STRING) - private TransactionStatus status = TransactionStatus.PROCESSING; - - @Column(name = "created_at") - private Date createdAt = new Date(); -} diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java b/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java deleted file mode 100644 index 5a16f0d..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.szut.casino.deposit; - -import de.szut.casino.user.UserEntity; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Optional; - -@Service -public interface TransactionRepository extends JpaRepository { - @Query("SELECT t FROM TransactionEntity t WHERE t.sessionId = ?1") - Optional findOneBySessionID(String sessionId); - - @Query("SELECT t FROM TransactionEntity t WHERE t.user = ?1") - List findAllByUserId(UserEntity id); - - @Query("SELECT t FROM TransactionEntity t WHERE t.user = ?1 ORDER BY t.createdAt DESC LIMIT ?2 OFFSET ?3") - List findByUserIdWithLimit(UserEntity userEntity, Integer limit, Integer offset); - - @Query("SELECT COUNT(t) > ?2 + ?3 FROM TransactionEntity t WHERE t.user = ?1") - Boolean hasMore(UserEntity userEntity, Integer limit, Integer offset); -} diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionService.java b/backend/src/main/java/de/szut/casino/deposit/TransactionService.java deleted file mode 100644 index 26f2e25..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionService.java +++ /dev/null @@ -1,70 +0,0 @@ -package de.szut.casino.deposit; - -import com.stripe.exception.StripeException; -import com.stripe.model.checkout.Session; -import com.stripe.param.checkout.SessionRetrieveParams; -import de.szut.casino.security.service.EmailService; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import jakarta.mail.MessagingException; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.math.BigDecimal; -import java.util.Optional; - -@Service -public class TransactionService { - private final TransactionRepository transactionRepository; - private final UserRepository userRepository; - private final EmailService emailService; - - public TransactionService(TransactionRepository transactionRepository, UserRepository userRepository, EmailService emailService) { - this.transactionRepository = transactionRepository; - this.userRepository = userRepository; - this.emailService = emailService; - } - - public void createTransaction( - UserEntity user, - String sessionID, - Double amount - ) { - TransactionEntity transaction = new TransactionEntity(); - - transaction.setUser(user); - transaction.setSessionId(sessionID); - transaction.setAmount(amount); - - transactionRepository.save(transaction); - } - - public void fulfillCheckout(String sessionID) throws StripeException, MessagingException, IOException { - SessionRetrieveParams params = SessionRetrieveParams.builder() - .addExpand("line_items") - .build(); - Session checkoutSession = Session.retrieve(sessionID, params, null); - - if (!"paid".equals(checkoutSession.getPaymentStatus())) { - return; - } - - Optional optionalTransaction = transactionRepository.findOneBySessionID(sessionID); - if (optionalTransaction.isEmpty()) { - throw new RuntimeException("Transaction not found"); - } - - TransactionEntity transaction = optionalTransaction.get(); - transaction.setStatus(TransactionStatus.SUCCEEDED); - - UserEntity user = transaction.getUser(); - Long amountTotal = checkoutSession.getAmountTotal(); - if (amountTotal != null) { - user.addBalance(BigDecimal.valueOf(amountTotal).movePointLeft(2)); - } - - userRepository.save(user); - transactionRepository.save(transaction); - emailService.sendDepositEmail(transaction); - } -} diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionStatus.java b/backend/src/main/java/de/szut/casino/deposit/TransactionStatus.java deleted file mode 100644 index 93ae142..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionStatus.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.szut.casino.deposit; - -public enum TransactionStatus { - PROCESSING, - SUCCEEDED, -} diff --git a/backend/src/main/java/de/szut/casino/deposit/WebhookController.java b/backend/src/main/java/de/szut/casino/deposit/WebhookController.java deleted file mode 100644 index 45ba4c1..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/WebhookController.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.szut.casino.deposit; - -import com.stripe.Stripe; -import com.stripe.exception.StripeException; -import com.stripe.model.Event; -import com.stripe.model.checkout.Session; -import com.stripe.net.Webhook; -import jakarta.annotation.PostConstruct; -import jakarta.mail.MessagingException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; -import java.util.Objects; - -@RestController -public class WebhookController { - private static final Logger logger = LoggerFactory.getLogger(WebhookController.class); - @Value("${stripe.secret.key}") - private String stripeSecretKey; - - @Value("${stripe.webhook.secret}") - private String webhookSecret; - - private final TransactionService transactionService; - - public WebhookController(TransactionService transactionService) { - this.transactionService = transactionService; - } - - @PostConstruct - public void init() { - Stripe.apiKey = stripeSecretKey; - } - - @PostMapping("/webhook") - public ResponseEntity webhook(@RequestBody String payload, @RequestHeader("Stripe-Signature") String sigHeader) throws StripeException, MessagingException, IOException { - Event event = Webhook.constructEvent(payload, sigHeader, webhookSecret); - - if (Objects.equals(event.getType(), "checkout.session.completed") || Objects.equals(event.getType(), "checkout.session.async_payment_succeeded")) { - Session session = (Session) event.getData().getObject(); - - this.transactionService.fulfillCheckout(session.getId()); - } - - return ResponseEntity.ok().body(null); - } -} diff --git a/backend/src/main/java/de/szut/casino/deposit/dto/AmountDto.java b/backend/src/main/java/de/szut/casino/deposit/dto/AmountDto.java deleted file mode 100644 index 1f1708e..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/dto/AmountDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.szut.casino.deposit.dto; - -import jakarta.validation.constraints.Min; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Setter -@Getter -@AllArgsConstructor -@NoArgsConstructor -public class AmountDto { - @Min(50) - private double amount; -} - diff --git a/backend/src/main/java/de/szut/casino/deposit/dto/SessionIdDto.java b/backend/src/main/java/de/szut/casino/deposit/dto/SessionIdDto.java deleted file mode 100644 index b3de1bc..0000000 --- a/backend/src/main/java/de/szut/casino/deposit/dto/SessionIdDto.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.szut.casino.deposit.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Setter -@Getter -@AllArgsConstructor -@NoArgsConstructor -public class SessionIdDto { - private String sessionId; -} - diff --git a/backend/src/main/java/de/szut/casino/dice/DiceController.java b/backend/src/main/java/de/szut/casino/dice/DiceController.java deleted file mode 100644 index 1341d96..0000000 --- a/backend/src/main/java/de/szut/casino/dice/DiceController.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.szut.casino.dice; - -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Optional; - -@RestController -public class DiceController { - private final UserService userService; - private final BalanceService balanceService; - private final DiceService diceService; - - public DiceController(UserService userService, BalanceService balanceService, DiceService diceService) { - this.userService = userService; - this.balanceService = balanceService; - this.diceService = diceService; - } - - @PostMapping("/dice") - public ResponseEntity rollDice(@RequestBody @Valid DiceDto diceDto) { - UserEntity user = userService.getCurrentUser(); - - if (!this.balanceService.hasFunds(user, diceDto)) { - throw new InsufficientFundsException(); - } - - return ResponseEntity.ok(diceService.play(user, diceDto)); - } -} diff --git a/backend/src/main/java/de/szut/casino/dice/DiceDto.java b/backend/src/main/java/de/szut/casino/dice/DiceDto.java deleted file mode 100644 index f0caf48..0000000 --- a/backend/src/main/java/de/szut/casino/dice/DiceDto.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.szut.casino.dice; - -import de.szut.casino.shared.dto.BetDto; -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Getter -@Setter -@NoArgsConstructor -public class DiceDto extends BetDto { - private boolean rollOver; - - @NotNull - @DecimalMin(value = "1.00") - @DecimalMax(value = "100") - private BigDecimal targetValue; - - public DiceDto(BigDecimal betAmount, boolean rollOver, BigDecimal targetValue) { - super(betAmount); - this.rollOver = rollOver; - this.targetValue = targetValue; - } -} diff --git a/backend/src/main/java/de/szut/casino/dice/DiceResult.java b/backend/src/main/java/de/szut/casino/dice/DiceResult.java deleted file mode 100644 index 65a7f69..0000000 --- a/backend/src/main/java/de/szut/casino/dice/DiceResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.szut.casino.dice; - -import lombok.Getter; -import lombok.Setter; - -import java.math.BigDecimal; - -@Setter -@Getter -public class DiceResult { - private boolean win; - private BigDecimal payout; - private BigDecimal rolledValue; - - public DiceResult(boolean win, BigDecimal payout, BigDecimal rolledValue) { - this.win = win; - this.payout = payout; - this.rolledValue = rolledValue; - } -} diff --git a/backend/src/main/java/de/szut/casino/dice/DiceService.java b/backend/src/main/java/de/szut/casino/dice/DiceService.java deleted file mode 100644 index 836620b..0000000 --- a/backend/src/main/java/de/szut/casino/dice/DiceService.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.szut.casino.dice; - -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.Random; - -@Service -public class DiceService { - private static final int MAX_DICE_VALUE = 100; - private final Random random; - private final BalanceService balanceService; - - public DiceService(Random random, BalanceService balanceService) { - this.random = random; - this.balanceService = balanceService; - } - - public DiceResult play(UserEntity user, DiceDto diceDto) { - balanceService.subtractFunds(user, diceDto.getBetAmount()); - - int rolledValue = random.nextInt(MAX_DICE_VALUE) + 1; - BigDecimal rolledValueDecimal = BigDecimal.valueOf(rolledValue); - - BigDecimal targetValue = diceDto.getTargetValue(); - boolean isRollOver = diceDto.isRollOver(); - - boolean winConditionMet = isWinConditionMet(rolledValueDecimal, targetValue, isRollOver); - - if (!winConditionMet) { - return new DiceResult(false, BigDecimal.ZERO, rolledValueDecimal); - } - - BigDecimal winChance = calculateWinChance(targetValue, isRollOver); - BigDecimal multiplier = calculateMultiplier(winChance); - - BigDecimal payout = diceDto.getBetAmount().multiply(multiplier); - balanceService.addFunds(user, payout); - - return new DiceResult(true, payout, rolledValueDecimal); - } - - private boolean isWinConditionMet(BigDecimal rolledValue, BigDecimal targetValue, boolean isRollOver) { - if (isRollOver) { - return rolledValue.compareTo(targetValue) > 0; - } - - return rolledValue.compareTo(targetValue) < 0; - } - - private BigDecimal calculateWinChance(BigDecimal targetValue, boolean isRollOver) { - if (isRollOver) { - return BigDecimal.valueOf(MAX_DICE_VALUE).subtract(targetValue); - } - - return targetValue.subtract(BigDecimal.ONE); - } - - private BigDecimal calculateMultiplier(BigDecimal winChance) { - if (winChance.compareTo(BigDecimal.ZERO) > 0) { - return BigDecimal.valueOf(MAX_DICE_VALUE - 1).divide(winChance, 4, RoundingMode.HALF_UP); - } - - return BigDecimal.ZERO; - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/ErrorDetails.java b/backend/src/main/java/de/szut/casino/exceptionHandling/ErrorDetails.java deleted file mode 100644 index cf287c7..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/ErrorDetails.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.szut.casino.exceptionHandling; - -import lombok.AllArgsConstructor; -import lombok.Data; - -import java.util.Date; - -@Data -@AllArgsConstructor -public class ErrorDetails { - private Date timestamp; - private String message; - private String details; -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/GlobalExceptionHandler.java b/backend/src/main/java/de/szut/casino/exceptionHandling/GlobalExceptionHandler.java deleted file mode 100644 index f07c03a..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/GlobalExceptionHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.szut.casino.exceptionHandling; - -import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException; -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.exceptionHandling.exceptions.UserBlackJackGameMismatchException; -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import jakarta.persistence.EntityExistsException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.context.request.WebRequest; - -import java.util.Date; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(UserNotFoundException.class) - public ResponseEntity handleUserNotFoundException(UserNotFoundException ex, WebRequest request) { - ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); - return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(InsufficientFundsException.class) - public ResponseEntity handleInsufficientFundsException(InsufficientFundsException ex, WebRequest request) { - ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); - return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(EntityExistsException.class) - public ResponseEntity handleEntityExistsException(EntityExistsException ex, WebRequest request) { - ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); - return new ResponseEntity<>(errorDetails, HttpStatus.CONFLICT); - } - - @ExceptionHandler(EmailNotVerifiedException.class) - public ResponseEntity handleEmailNotVerifiedException(EmailNotVerifiedException ex, WebRequest request) { - ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); - return new ResponseEntity<>(errorDetails, HttpStatus.UNAUTHORIZED); - } - - @ExceptionHandler(UserBlackJackGameMismatchException.class) - public ResponseEntity handleUserBlackJackGameMismatchException(UserBlackJackGameMismatchException ex, WebRequest request) { - ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); - return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND); - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/EmailNotVerifiedException.java b/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/EmailNotVerifiedException.java deleted file mode 100644 index af97d4e..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/EmailNotVerifiedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.szut.casino.exceptionHandling.exceptions; - -public class EmailNotVerifiedException extends Exception { - public EmailNotVerifiedException() { - super("Email not verified"); - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/InsufficientFundsException.java b/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/InsufficientFundsException.java deleted file mode 100644 index 7c87acc..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/InsufficientFundsException.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.szut.casino.exceptionHandling.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(value = HttpStatus.BAD_REQUEST) -public class InsufficientFundsException extends RuntimeException { - public InsufficientFundsException() { - super("insufficient funds"); - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/OAuth2AuthenticationProcessingException.java b/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/OAuth2AuthenticationProcessingException.java deleted file mode 100644 index b4f421e..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/OAuth2AuthenticationProcessingException.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.szut.casino.exceptionHandling.exceptions; - -import org.springframework.security.core.AuthenticationException; - -public class OAuth2AuthenticationProcessingException extends AuthenticationException { - public OAuth2AuthenticationProcessingException(String msg) { - super(msg); - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserBlackJackGameMismatchException.java b/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserBlackJackGameMismatchException.java deleted file mode 100644 index 22a93cc..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserBlackJackGameMismatchException.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.szut.casino.exceptionHandling.exceptions; - -public class UserBlackJackGameMismatchException extends RuntimeException { - public UserBlackJackGameMismatchException(Long gameId) { - super(String.format("Blackjack game with ID %d not found or does not belong to the current user.", gameId)); - } -} diff --git a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserNotFoundException.java b/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserNotFoundException.java deleted file mode 100644 index d843af7..0000000 --- a/backend/src/main/java/de/szut/casino/exceptionHandling/exceptions/UserNotFoundException.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.szut.casino.exceptionHandling.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(value = HttpStatus.NOT_FOUND) -public class UserNotFoundException extends RuntimeException { - public UserNotFoundException() { - super("User not found"); - } -} diff --git a/backend/src/main/java/de/szut/casino/health/HealthController.java b/backend/src/main/java/de/szut/casino/health/HealthController.java deleted file mode 100644 index da05352..0000000 --- a/backend/src/main/java/de/szut/casino/health/HealthController.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.szut.casino.health; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; - -@RestController -public class HealthController { - - @GetMapping("/health") - public Map healthCheck() { - return Map.of("status", "UP"); - } -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java b/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java deleted file mode 100644 index 10e1b4e..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.szut.casino.lootboxes; - -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class CreateLootBoxDto { - @NotEmpty(message = "Loot box name cannot be empty") - @Size(min = 3, max = 50, message = "Loot box name must be between 3 and 50 characters") - private String name; - - @NotNull(message = "Price cannot be null") - @DecimalMin(value = "0.01", message = "Price must be greater than 0") - private BigDecimal price; - - private List rewards = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java b/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java deleted file mode 100644 index 0dbe819..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.szut.casino.lootboxes; - -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class CreateRewardDto { - @NotNull(message = "Reward value cannot be null") - @DecimalMin(value = "0.00", message = "Reward value must be positive") - private BigDecimal value; - - @NotNull(message = "Probability cannot be null") - @DecimalMin(value = "0.0", message = "Probability must be at least 0.0") - @DecimalMax(value = "1.0", message = "Probability must be at most 1.0") - private BigDecimal probability; -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java deleted file mode 100644 index 4b7d971..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java +++ /dev/null @@ -1,85 +0,0 @@ -package de.szut.casino.lootboxes; - -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -@RestController -public class LootBoxController { - private final LootBoxRepository lootBoxRepository; - private final UserService userService; - private final LootBoxService lootBoxService; - - public LootBoxController(LootBoxRepository lootBoxRepository, UserService userService, LootBoxService lootBoxService) { - this.lootBoxRepository = lootBoxRepository; - this.userService = userService; - this.lootBoxService = lootBoxService; - } - - @GetMapping("/lootboxes") - public List getAllLootBoxes() { - return lootBoxRepository.findAll(); - } - - @PostMapping("/lootboxes/{id}") - public ResponseEntity purchaseLootBox(@PathVariable Long id) { - Optional optionalLootBox = lootBoxRepository.findById(id); - if (optionalLootBox.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - LootBoxEntity lootBox = optionalLootBox.get(); - UserEntity user = userService.getCurrentUser(); - - if (lootBoxService.hasSufficientBalance(user, lootBox.getPrice())) { - throw new InsufficientFundsException(); - } - - RewardEntity reward = lootBoxService.determineReward(lootBox); - lootBoxService.handleBalance(user, lootBox, reward); - - return ResponseEntity.ok(reward); - } - - @PostMapping("/lootboxes") - public ResponseEntity createLootbox(@RequestBody @Valid CreateLootBoxDto createLootBoxDto) { - List rewardEntities = new ArrayList<>(); - - for (CreateRewardDto createRewardDto : createLootBoxDto.getRewards()) { - rewardEntities.add(new RewardEntity(createRewardDto.getValue(), createRewardDto.getProbability())); - } - - LootBoxEntity lootBoxEntity = new LootBoxEntity( - createLootBoxDto.getName(), - createLootBoxDto.getPrice(), - rewardEntities - ); - - this.lootBoxRepository.save(lootBoxEntity); - - return ResponseEntity.ok(lootBoxEntity); - } - - @DeleteMapping("/lootboxes/{id}") - public ResponseEntity deleteLootbox(@PathVariable Long id) { - Optional optionalLootBox = lootBoxRepository.findById(id); - if (optionalLootBox.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - LootBoxEntity lootBox = optionalLootBox.get(); - lootBoxRepository.delete(lootBox); - - return ResponseEntity.ok(Collections.singletonMap("message", "successfully deleted lootbox")); - } - -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java deleted file mode 100644 index 8a3e9a9..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.szut.casino.lootboxes; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -@Entity -@Getter -@Setter -@NoArgsConstructor -public class LootBoxEntity { - - public LootBoxEntity(String name, BigDecimal price, List rewards) { - this.name = name; - this.price = price; - this.rewards = rewards; - } - - @Id - @GeneratedValue - private Long id; - - private String name; - - @Column(precision = 19, scale = 2) - private BigDecimal price; - - @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable( - name = "lootbox_reward", - joinColumns = @JoinColumn(name = "lootbox_id"), - inverseJoinColumns = @JoinColumn(name = "reward_id") - ) - private List rewards = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java deleted file mode 100644 index 472388e..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.szut.casino.lootboxes; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Service; - -@Service -public interface LootBoxRepository extends JpaRepository { -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java deleted file mode 100644 index 647b69b..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.szut.casino.lootboxes; - -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; - -@Service -public class LootBoxService { - private final UserRepository userRepository; - - public LootBoxService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public boolean hasSufficientBalance(UserEntity user, BigDecimal price) { - return user.getBalance().compareTo(price) < 0; - } - - public RewardEntity determineReward(LootBoxEntity lootBox) { - double randomValue = Math.random(); - BigDecimal cumulativeProbability = BigDecimal.ZERO; - - for (RewardEntity reward : lootBox.getRewards()) { - cumulativeProbability = cumulativeProbability.add(reward.getProbability()); - if (randomValue <= cumulativeProbability.doubleValue()) { - return reward; - } - } - - return lootBox.getRewards().getLast(); - } - - public void handleBalance(UserEntity user, LootBoxEntity lootBox, RewardEntity reward) { - user.setBalance(user.getBalance().subtract(lootBox.getPrice())); - user.setBalance(user.getBalance().add(reward.getValue())); - userRepository.save(user); - } -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java deleted file mode 100644 index 1abd2df..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.szut.casino.lootboxes; - -import com.fasterxml.jackson.annotation.JsonBackReference; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -@Getter -@Setter -@Entity -@NoArgsConstructor -public class RewardEntity { - - public RewardEntity(BigDecimal value, BigDecimal probability) { - this.value = value; - this.probability = probability; - } - - @Id - @GeneratedValue - private Long id; - - @Column(precision = 19, scale = 2) - private BigDecimal value; - - @Column(precision = 5, scale = 2) - private BigDecimal probability; - - @ManyToMany(mappedBy = "rewards") - @JsonBackReference - private List lootBoxes = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java deleted file mode 100644 index 7878000..0000000 --- a/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.szut.casino.lootboxes; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Service; - -@Service -public interface RewardRepository extends JpaRepository { -} diff --git a/backend/src/main/java/de/szut/casino/security/AuthController.java b/backend/src/main/java/de/szut/casino/security/AuthController.java deleted file mode 100644 index f0387c7..0000000 --- a/backend/src/main/java/de/szut/casino/security/AuthController.java +++ /dev/null @@ -1,60 +0,0 @@ -package de.szut.casino.security; - -import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException; -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.dto.LoginRequestDto; -import de.szut.casino.security.dto.ResetPasswordDto; -import de.szut.casino.security.service.AuthService; -import de.szut.casino.user.dto.CreateUserDto; -import de.szut.casino.user.dto.GetUserDto; -import jakarta.mail.MessagingException; -import jakarta.validation.Valid; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; - -@RestController -@RequestMapping("/auth") -public class AuthController { - - - private final AuthService authService; - - public AuthController(AuthService authService) { - this.authService = authService; - } - - @PostMapping("/login") - public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequestDto loginRequest) throws EmailNotVerifiedException { - AuthResponseDto response = authService.login(loginRequest); - return ResponseEntity.ok(response); - } - - @PostMapping("/register") - public ResponseEntity registerUser(@Valid @RequestBody CreateUserDto signUpRequest) throws MessagingException, IOException { - GetUserDto response = authService.register(signUpRequest); - return ResponseEntity.ok(response); - } - - @PostMapping("/verify") - public ResponseEntity verifyEmail(@RequestParam("token") String token) throws MessagingException, IOException { - if (authService.verifyEmail(token)) { - return ResponseEntity.badRequest().build(); - } - - return ResponseEntity.ok().build(); - } - - @PostMapping("/recover-password") - public ResponseEntity recoverPassword(@RequestParam("email") String email) throws MessagingException, IOException { - authService.recoverPassword(email); - return ResponseEntity.ok().build(); - } - - @PostMapping("/reset-password") - public ResponseEntity resetPassword(@Valid @RequestBody ResetPasswordDto passwordDto) throws MessagingException, IOException { - authService.resetPassword(passwordDto); - return ResponseEntity.ok().build(); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/CorsFilter.java b/backend/src/main/java/de/szut/casino/security/CorsFilter.java deleted file mode 100644 index b1c1b3b..0000000 --- a/backend/src/main/java/de/szut/casino/security/CorsFilter.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.szut.casino.security; - -import jakarta.servlet.*; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.io.IOException; - -@Component -@Order(Ordered.HIGHEST_PRECEDENCE) -public class CorsFilter implements Filter { - - @Value("${app.frontend-host}") - private String frontendHost; - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - - HttpServletResponse response = (HttpServletResponse) res; - HttpServletRequest request = (HttpServletRequest) req; - - response.setHeader("Access-Control-Allow-Origin", frontendHost); - response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS"); - response.setHeader("Access-Control-Allow-Headers", "*"); - response.setHeader("Access-Control-Expose-Headers", "*"); - response.setHeader("Access-Control-Allow-Credentials", "true"); - response.setHeader("Access-Control-Max-Age", "3600"); - - if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { - response.setStatus(HttpServletResponse.SC_OK); - return; - } - - chain.doFilter(req, res); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java b/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java deleted file mode 100644 index 1997ac7..0000000 --- a/backend/src/main/java/de/szut/casino/security/CustomJwtAuthenticationConverter.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.szut.casino.security; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; - -public class CustomJwtAuthenticationConverter implements Converter { - - @Override - public AbstractAuthenticationToken convert(Jwt source) { - JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); - JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); - converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); - - return converter.convert(source); - } - - public Converter andThen(Converter after) { - return Converter.super.andThen(after); - } -} - diff --git a/backend/src/main/java/de/szut/casino/security/SecurityConfig.java b/backend/src/main/java/de/szut/casino/security/SecurityConfig.java deleted file mode 100644 index 9268cf2..0000000 --- a/backend/src/main/java/de/szut/casino/security/SecurityConfig.java +++ /dev/null @@ -1,94 +0,0 @@ -package de.szut.casino.security; - -import de.szut.casino.security.jwt.JwtAuthenticationFilter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import java.util.Arrays; -import java.util.List; - -@Configuration -@EnableWebSecurity -@EnableMethodSecurity -public class SecurityConfig { - - @Value("${app.frontend-host}") - private String frontendHost; - - private final UserDetailsService userDetailsService; - private final JwtAuthenticationFilter jwtAuthenticationFilter; - - public SecurityConfig(UserDetailsService userDetailsService, JwtAuthenticationFilter jwtAuthenticationFilter) { - this.userDetailsService = userDetailsService; - this.jwtAuthenticationFilter = jwtAuthenticationFilter; - } - - - @Bean - public DaoAuthenticationProvider authenticationProvider() { - DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); - - authProvider.setUserDetailsService(userDetailsService); - authProvider.setPasswordEncoder(passwordEncoder()); - - return authProvider; - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { - return authConfig.getAuthenticationManager(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http - .cors(cors -> cors.configurationSource(corsConfigurationSource())) - .csrf(csrf -> csrf.disable()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(auth -> { - auth.requestMatchers("/auth/**", "/webhook", "/swagger/**", "/swagger-ui/**", "/health", "/error", "/oauth2/**").permitAll() - .requestMatchers(org.springframework.http.HttpMethod.OPTIONS, "/**").permitAll() - .anyRequest().authenticated(); - }) - .authenticationProvider(authenticationProvider()) - .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - - return http.build(); - } - - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(List.of(this.frontendHost)); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); - configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Accept", "Origin", "X-Requested-With", "Access-Control-Request-Method", "Access-Control-Request-Headers", "x-auth-token")); - configuration.setExposedHeaders(Arrays.asList("Authorization", "Content-Type", "x-auth-token", "Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers")); - configuration.setAllowCredentials(true); - configuration.setMaxAge(3600L); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } -} - diff --git a/backend/src/main/java/de/szut/casino/security/dto/AuthResponseDto.java b/backend/src/main/java/de/szut/casino/security/dto/AuthResponseDto.java deleted file mode 100644 index 4dfe79a..0000000 --- a/backend/src/main/java/de/szut/casino/security/dto/AuthResponseDto.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.szut.casino.security.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class AuthResponseDto { - private String token; - private String tokenType = "Bearer"; - - public AuthResponseDto(String token) { - this.token = token; - } -} diff --git a/backend/src/main/java/de/szut/casino/security/dto/LoginRequestDto.java b/backend/src/main/java/de/szut/casino/security/dto/LoginRequestDto.java deleted file mode 100644 index 767a6d3..0000000 --- a/backend/src/main/java/de/szut/casino/security/dto/LoginRequestDto.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.szut.casino.security.dto; - -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class LoginRequestDto { - @NotBlank(message = "Username or email is required") - private String usernameOrEmail; - - @NotBlank(message = "Password is required") - private String password; -} diff --git a/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java b/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java deleted file mode 100644 index 192d928..0000000 --- a/backend/src/main/java/de/szut/casino/security/dto/ResetPasswordDto.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.szut.casino.security.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -public class ResetPasswordDto { - private String token; - private String password; -} diff --git a/backend/src/main/java/de/szut/casino/security/jwt/JwtAuthenticationFilter.java b/backend/src/main/java/de/szut/casino/security/jwt/JwtAuthenticationFilter.java deleted file mode 100644 index 4766f4a..0000000 --- a/backend/src/main/java/de/szut/casino/security/jwt/JwtAuthenticationFilter.java +++ /dev/null @@ -1,65 +0,0 @@ -package de.szut.casino.security.jwt; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; - -@Component -public class JwtAuthenticationFilter extends OncePerRequestFilter { - - private final JwtUtils jwtUtils; - private final UserDetailsService userDetailsService; - - public JwtAuthenticationFilter(JwtUtils jwtUtils, UserDetailsService userDetailsService) { - this.jwtUtils = jwtUtils; - this.userDetailsService = userDetailsService; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - try { - String jwt = parseJwt(request); - if (jwt != null) { - String username = jwtUtils.extractUsername(jwt); - - if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - - if (jwtUtils.validateToken(jwt, userDetails)) { - UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities()); - - authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authToken); - } - } - } - } catch (Exception e) { - logger.error("Cannot set user authentication: {}", e); - } - - filterChain.doFilter(request, response); - } - - private String parseJwt(HttpServletRequest request) { - String headerAuth = request.getHeader("Authorization"); - - if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { - return headerAuth.substring(7); - } - - return null; - } -} diff --git a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java b/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java deleted file mode 100644 index 1a7d08d..0000000 --- a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java +++ /dev/null @@ -1,109 +0,0 @@ -package de.szut.casino.security.jwt; - -import de.szut.casino.security.oauth2.UserPrincipal; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.security.Keys; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Component; - -import java.security.Key; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -@Component -public class JwtUtils { - private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); - - @Value("${jwt.secret}") - private String jwtSecret; - - @Value("${jwt.expiration.ms}") - private int jwtExpirationMs; - - private Key getSigningKey() { - return Keys.hmacShaKeyFor(jwtSecret.getBytes()); - } - - public String generateToken(Authentication authentication) { - String subject = null; - Map claims = new HashMap<>(); - - if (authentication.getPrincipal() instanceof UserPrincipal) { - UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); - subject = userPrincipal.getEmail(); - claims.put("id", userPrincipal.getId()); - claims.put("username", userPrincipal.getDisplayUsername()); - logger.info("Generating token for UserPrincipal: {}", subject); - } else if (authentication.getPrincipal() instanceof OAuth2User) { - OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal(); - subject = (String) oauth2User.getAttributes().get("email"); - logger.info("Generating token for OAuth2User: {}", subject); - } else { - UserDetails userDetails = (UserDetails) authentication.getPrincipal(); - subject = userDetails.getUsername(); - logger.info("Generating token for UserDetails: {}", subject); - } - - return createToken(claims, subject); - } - - public String generateToken(String username) { - Map claims = new HashMap<>(); - return createToken(claims, username); - } - - private String createToken(Map claims, String subject) { - Date now = new Date(); - logger.info("now: {}", now); - logger.info("jwtExpirationMs: {}", jwtExpirationMs); - logger.info("expiryDate: {}", new Date(now.getTime() + jwtExpirationMs)); - Date expiryDate = new Date(now.getTime() + jwtExpirationMs); - - return Jwts.builder() - .setClaims(claims) - .setSubject(subject) - .setIssuedAt(now) - .setExpiration(expiryDate) - .signWith(getSigningKey(), SignatureAlgorithm.HS256) - .compact(); - } - - public String extractUsername(String token) { - return extractClaim(token, Claims::getSubject); - } - - public Date extractExpiration(String token) { - return extractClaim(token, Claims::getExpiration); - } - - public T extractClaim(String token, Function claimsResolver) { - final Claims claims = extractAllClaims(token); - return claimsResolver.apply(claims); - } - - private Claims extractAllClaims(String token) { - return Jwts.parserBuilder() - .setSigningKey(getSigningKey()) - .build() - .parseClaimsJws(token) - .getBody(); - } - - private Boolean isTokenExpired(String token) { - return extractExpiration(token).before(new Date()); - } - - public Boolean validateToken(String token, UserDetails userDetails) { - final String username = extractUsername(token); - return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/CustomOAuth2UserService.java b/backend/src/main/java/de/szut/casino/security/oauth2/CustomOAuth2UserService.java deleted file mode 100644 index a8bda84..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/CustomOAuth2UserService.java +++ /dev/null @@ -1,106 +0,0 @@ -package de.szut.casino.security.oauth2; - -import de.szut.casino.exceptionHandling.exceptions.OAuth2AuthenticationProcessingException; -import de.szut.casino.user.AuthProvider; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.springframework.security.authentication.InternalAuthenticationServiceException; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; - -import java.math.BigDecimal; -import java.util.Optional; -import java.util.UUID; - -@Service -public class CustomOAuth2UserService extends DefaultOAuth2UserService { - - private final UserRepository userRepository; - private final PasswordEncoder oauth2PasswordEncoder; - - public CustomOAuth2UserService(UserRepository userRepository, PasswordEncoder oauth2PasswordEncoder) { - this.userRepository = userRepository; - this.oauth2PasswordEncoder = oauth2PasswordEncoder; - } - - @Override - public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException { - OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest); - - try { - return processOAuth2User(oAuth2UserRequest, oAuth2User); - } catch (AuthenticationException ex) { - throw ex; - } catch (Exception ex) { - throw new InternalAuthenticationServiceException(ex.getMessage(), ex.getCause()); - } - } - - private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) { - String registrationId = oAuth2UserRequest.getClientRegistration().getRegistrationId(); - OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(registrationId, oAuth2User.getAttributes()); - - String email = oAuth2UserInfo.getEmail(); - if (StringUtils.isEmpty(email)) { - email = oAuth2UserInfo.getName() + "@github.user"; - } - - Optional userOptional = userRepository.findByEmail(email); - UserEntity user; - - if (userOptional.isPresent()) { - user = userOptional.get(); - - if (!user.getProvider().equals(AuthProvider.valueOf(registrationId.toUpperCase()))) { - throw new OAuth2AuthenticationProcessingException("You're signed up with " + - user.getProvider() + ". Please use your " + user.getProvider() + - " account to login."); - } - - user = updateExistingUser(user, oAuth2UserInfo); - } else { - user = registerNewUser(oAuth2UserRequest, oAuth2UserInfo, email); - } - - return UserPrincipal.create(user, oAuth2User.getAttributes()); - } - - private UserEntity registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo, String email) { - UserEntity user = new UserEntity(); - - String username = oAuth2UserInfo.getName(); - if (StringUtils.isEmpty(username)) { - username = "github_" + oAuth2UserInfo.getId(); - } - - if (userRepository.findByUsername(username).isPresent()) { - username = username + "_" + UUID.randomUUID().toString().substring(0, 8); - } - - user.setProvider(AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId().toUpperCase())); - user.setProviderId(oAuth2UserInfo.getId()); - user.setUsername(username); - user.setEmail(email); - user.setEmailVerified(true); - - String randomPassword = UUID.randomUUID().toString(); - user.setPassword(oauth2PasswordEncoder.encode(randomPassword)); - - user.setBalance(new BigDecimal("100.00")); // Starting balance - - return userRepository.save(user); - } - - private UserEntity updateExistingUser(UserEntity existingUser, OAuth2UserInfo oAuth2UserInfo) { - if (!StringUtils.isEmpty(oAuth2UserInfo.getName())) { - existingUser.setUsername(oAuth2UserInfo.getName()); - } - return userRepository.save(existingUser); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2AuthenticationSuccessHandler.java b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2AuthenticationSuccessHandler.java deleted file mode 100644 index 75eb6b6..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2AuthenticationSuccessHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.szut.casino.security.oauth2; - -import de.szut.casino.security.jwt.JwtUtils; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.stereotype.Component; -import org.springframework.web.util.UriComponentsBuilder; - -import java.io.IOException; - -@Component -public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - private static final Logger logger = LoggerFactory.getLogger(OAuth2AuthenticationSuccessHandler.class); - - @Value("${app.oauth2.authorizedRedirectUris}") - private String redirectUri; - - private final JwtUtils jwtUtils; - - public OAuth2AuthenticationSuccessHandler(JwtUtils jwtUtils) { - this.jwtUtils = jwtUtils; - } - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException { - String targetUrl = determineTargetUrl(authentication); - - logger.info("OAuth2 Authentication successful, redirecting to: {}", targetUrl); - - if (response.isCommitted()) { - logger.debug("Response has already been committed. Unable to redirect to " + targetUrl); - return; - } - - clearAuthenticationAttributes(request); - getRedirectStrategy().sendRedirect(request, response, targetUrl); - } - - private String determineTargetUrl(Authentication authentication) { - String token = jwtUtils.generateToken(authentication); - - if (authentication.getPrincipal() instanceof UserPrincipal) { - UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); - logger.info("User authenticated: ID={}, Email={}", userPrincipal.getId(), userPrincipal.getEmail()); - } - - return UriComponentsBuilder.fromUriString(redirectUri) - .queryParam("token", token) - .build().toUriString(); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2Config.java b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2Config.java deleted file mode 100644 index 32104ed..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2Config.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.szut.casino.security.oauth2; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; - -@Configuration -public class OAuth2Config { - - @Bean - public PasswordEncoder oauth2PasswordEncoder() { - return new BCryptPasswordEncoder(); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfo.java b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfo.java deleted file mode 100644 index 14e2bcc..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfo.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.szut.casino.security.oauth2; - -import lombok.Getter; - -import java.util.Map; - -@Getter -public abstract class OAuth2UserInfo { - protected Map attributes; - - public OAuth2UserInfo(Map attributes) { - this.attributes = attributes; - } - - public abstract String getId(); - - public abstract String getName(); - - public abstract String getEmail(); -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java b/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java deleted file mode 100644 index 66633e0..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/OAuth2UserInfoFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.szut.casino.security.oauth2; - -import de.szut.casino.exceptionHandling.exceptions.OAuth2AuthenticationProcessingException; -import de.szut.casino.security.oauth2.github.GitHubOAuth2UserInfo; -import de.szut.casino.security.oauth2.google.GoogleOAuth2UserInfo; -import de.szut.casino.user.AuthProvider; - -import java.util.Map; - -public class OAuth2UserInfoFactory { - - public static OAuth2UserInfo getOAuth2UserInfo(String registrationId, Map attributes) { - if (registrationId.equalsIgnoreCase(AuthProvider.GITHUB.toString())) { - return new GitHubOAuth2UserInfo(attributes); - } else if (registrationId.equalsIgnoreCase(AuthProvider.GOOGLE.toString())) { - return new GoogleOAuth2UserInfo(attributes); - } else { - throw new OAuth2AuthenticationProcessingException("Sorry! Login with " + registrationId + " is not supported yet."); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/UserPrincipal.java b/backend/src/main/java/de/szut/casino/security/oauth2/UserPrincipal.java deleted file mode 100644 index 8ec25e0..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/UserPrincipal.java +++ /dev/null @@ -1,102 +0,0 @@ -package de.szut.casino.security.oauth2; - -import de.szut.casino.user.UserEntity; -import lombok.Getter; -import lombok.Setter; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.core.user.OAuth2User; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class UserPrincipal implements OAuth2User, UserDetails { - @Getter - private Long id; - @Getter - private String email; - private String username; - private String password; - private Collection authorities; - @Setter - private Map attributes; - - public UserPrincipal(Long id, String email, String username, String password, Collection authorities) { - this.id = id; - this.email = email; - this.username = username; - this.password = password; - this.authorities = authorities; - } - - public static UserPrincipal create(UserEntity user) { - List authorities = Collections. - singletonList(new SimpleGrantedAuthority("ROLE_USER")); - - return new UserPrincipal( - user.getId(), - user.getEmail(), - user.getUsername(), - user.getPassword(), - authorities - ); - } - - public static UserPrincipal create(UserEntity user, Map attributes) { - UserPrincipal userPrincipal = UserPrincipal.create(user); - userPrincipal.setAttributes(attributes); - return userPrincipal; - } - - @Override - public String getPassword() { - return password; - } - - @Override - public String getUsername() { - return email; - } - - public String getDisplayUsername() { - return username; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - @Override - public Map getAttributes() { - return attributes; - } - - @Override - public String getName() { - return String.valueOf(id); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubController.java b/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubController.java deleted file mode 100644 index 2fe6279..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubController.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.szut.casino.security.oauth2.github; - -import de.szut.casino.security.dto.AuthResponseDto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.view.RedirectView; - -@RestController -@RequestMapping("/oauth2/github") -public class GitHubController { - private static final Logger logger = LoggerFactory.getLogger(GitHubController.class); - - @Value("${spring.security.oauth2.client.registration.github.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.provider.github.authorization-uri}") - private String authorizationUri; - - @Value("${spring.security.oauth2.client.registration.github.redirect-uri}") - private String redirectUri; - - private final GitHubService githubService; - - public GitHubController(GitHubService githubService) { - this.githubService = githubService; - } - - @GetMapping("/authorize") - public RedirectView authorizeGithub() { - logger.info("Redirecting to GitHub for authorization"); - - String authUrl = authorizationUri + - "?client_id=" + clientId + - "&redirect_uri=" + redirectUri + - "&scope=user:email,read:user"; - - return new RedirectView(authUrl); - } - - - @PostMapping("/callback") - public ResponseEntity githubCallback(@RequestBody GithubCallbackDto githubCallbackDto) { - String code = githubCallbackDto.getCode(); - AuthResponseDto response = githubService.processGithubCode(code); - return ResponseEntity.ok(response); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubOAuth2UserInfo.java b/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubOAuth2UserInfo.java deleted file mode 100644 index c764fc7..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubOAuth2UserInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.szut.casino.security.oauth2.github; - -import de.szut.casino.security.oauth2.OAuth2UserInfo; - -import java.util.Map; - -public class GitHubOAuth2UserInfo extends OAuth2UserInfo { - - public GitHubOAuth2UserInfo(Map attributes) { - super(attributes); - } - - @Override - public String getId() { - return ((Integer) attributes.get("id")).toString(); - } - - @Override - public String getName() { - return (String) attributes.get("name"); - } - - @Override - public String getEmail() { - return (String) attributes.get("email"); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubService.java b/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubService.java deleted file mode 100644 index 3c7d22f..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/github/GitHubService.java +++ /dev/null @@ -1,162 +0,0 @@ -package de.szut.casino.security.oauth2.github; - -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.jwt.JwtUtils; -import de.szut.casino.user.AuthProvider; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -import java.math.BigDecimal; -import java.util.*; - -@Service -public class GitHubService { - @Value("${spring.security.oauth2.client.registration.github.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.registration.github.client-secret}") - private String clientSecret; - - private final AuthenticationManager authenticationManager; - private final UserRepository userRepository; - private final JwtUtils jwtUtils; - private final PasswordEncoder oauth2PasswordEncoder; - - public GitHubService(AuthenticationManager authenticationManager, UserRepository userRepository, JwtUtils jwtUtils, PasswordEncoder oauth2PasswordEncoder) { - this.authenticationManager = authenticationManager; - this.userRepository = userRepository; - this.jwtUtils = jwtUtils; - this.oauth2PasswordEncoder = oauth2PasswordEncoder; - } - - public AuthResponseDto processGithubCode(String code) { - try { - RestTemplate restTemplate = new RestTemplate(); - - Map requestBody = new HashMap<>(); - requestBody.put("client_id", clientId); - requestBody.put("client_secret", clientSecret); - requestBody.put("code", code); - - HttpHeaders headers = new HttpHeaders(); - headers.set("Accept", "application/json"); - - HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); - - ResponseEntity response = restTemplate.exchange( - "https://github.com/login/oauth/access_token", - HttpMethod.POST, - requestEntity, - Map.class - ); - - Map responseBody = response.getBody(); - - if (responseBody.containsKey("error")) { - String error = (String) responseBody.get("error"); - String errorDescription = (String) responseBody.get("error_description"); - - throw new RuntimeException("GitHub OAuth error: " + errorDescription); - } - - String accessToken = (String) responseBody.get("access_token"); - if (accessToken == null || accessToken.isEmpty()) { - - throw new RuntimeException("Failed to receive access token from GitHub"); - } - - HttpHeaders userInfoHeaders = new HttpHeaders(); - userInfoHeaders.set("Authorization", "Bearer " + accessToken); - - HttpEntity userInfoRequestEntity = new HttpEntity<>(null, userInfoHeaders); - - ResponseEntity userResponse = restTemplate.exchange( - "https://api.github.com/user", - HttpMethod.GET, - userInfoRequestEntity, - Map.class - ); - - Map userAttributes = userResponse.getBody(); - - HttpHeaders emailsHeaders = new HttpHeaders(); - emailsHeaders.set("Authorization", "Bearer " + accessToken); - - HttpEntity emailsRequestEntity = new HttpEntity<>(null, emailsHeaders); - - ResponseEntity emailsResponse = restTemplate.exchange( - "https://api.github.com/user/emails", - HttpMethod.GET, - emailsRequestEntity, - List.class - ); - - List> emails = emailsResponse.getBody(); - String email = null; - - for (Map emailInfo : emails) { - Boolean primary = (Boolean) emailInfo.get("primary"); - if (primary != null && primary) { - email = (String) emailInfo.get("email"); - break; - } - } - - if (email == null && !emails.isEmpty()) { - email = (String) emails.get(0).get("email"); - } - - String githubId = userAttributes.get("id").toString(); - String username = (String) userAttributes.get("login"); - - Optional userOptional = userRepository.findByProviderId(githubId); - UserEntity user; - - if (userOptional.isPresent()) { - user = userOptional.get(); - } else { - userOptional = userRepository.findByEmail(email); - - if (userOptional.isPresent()) { - user = userOptional.get(); - user.setProvider(AuthProvider.GITHUB); - user.setProviderId(githubId); - } else { - user = new UserEntity(); - user.setEmail(email); - user.setUsername(username); - user.setProvider(AuthProvider.GITHUB); - user.setProviderId(githubId); - user.setEmailVerified(true); - - user.setBalance(new BigDecimal("1000.00")); - } - } - - String randomPassword = UUID.randomUUID().toString(); - user.setPassword(oauth2PasswordEncoder.encode(randomPassword)); - - userRepository.save(user); - - Authentication authentication = this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), randomPassword)); - - String token = jwtUtils.generateToken(authentication); - - return new AuthResponseDto(token); - - } catch (Exception e) { - throw new RuntimeException("Failed to process GitHub authentication", e); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/github/GithubCallbackDto.java b/backend/src/main/java/de/szut/casino/security/oauth2/github/GithubCallbackDto.java deleted file mode 100644 index 620a708..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/github/GithubCallbackDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.szut.casino.security.oauth2.github; - -import lombok.Data; - -@Data -public class GithubCallbackDto { - private String code; -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleController.java b/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleController.java deleted file mode 100644 index 9a50f65..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleController.java +++ /dev/null @@ -1,51 +0,0 @@ -package de.szut.casino.security.oauth2.google; - -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.oauth2.github.GithubCallbackDto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.view.RedirectView; - -@RestController -@RequestMapping("/oauth2/google") -public class GoogleController { - private static final Logger logger = LoggerFactory.getLogger(GoogleController.class); - - @Value("${spring.security.oauth2.client.registration.google.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.provider.google.authorization-uri}") - private String authorizationUri; - - @Value("${spring.security.oauth2.client.registration.google.redirect-uri}") - private String redirectUri; - - private final GoogleService googleService; - - public GoogleController(GoogleService googleService) { - this.googleService = googleService; - } - - @GetMapping("/authorize") - public RedirectView authorizeGoogle() { - logger.info("Redirecting to Google for authorization"); - - String authUrl = authorizationUri + - "?client_id=" + clientId + - "&redirect_uri=" + redirectUri + - "&response_type=code" + - "&scope=email profile"; - - return new RedirectView(authUrl); - } - - @PostMapping("/callback") - public ResponseEntity googleCallback(@RequestBody GithubCallbackDto callbackDto) { - String code = callbackDto.getCode(); - AuthResponseDto response = googleService.processGoogleCode(code); - return ResponseEntity.ok(response); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleOAuth2UserInfo.java b/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleOAuth2UserInfo.java deleted file mode 100644 index 819a9b3..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleOAuth2UserInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.szut.casino.security.oauth2.google; - -import de.szut.casino.security.oauth2.OAuth2UserInfo; - -import java.util.Map; - -public class GoogleOAuth2UserInfo extends OAuth2UserInfo { - - public GoogleOAuth2UserInfo(Map attributes) { - super(attributes); - } - - @Override - public String getId() { - return (String) attributes.get("sub"); - } - - @Override - public String getName() { - return (String) attributes.get("name"); - } - - @Override - public String getEmail() { - return (String) attributes.get("email"); - } -} diff --git a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleService.java b/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleService.java deleted file mode 100644 index f369052..0000000 --- a/backend/src/main/java/de/szut/casino/security/oauth2/google/GoogleService.java +++ /dev/null @@ -1,165 +0,0 @@ -package de.szut.casino.security.oauth2.google; - -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.jwt.JwtUtils; -import de.szut.casino.user.AuthProvider; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -import java.math.BigDecimal; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -@Service -public class GoogleService { - private static final Logger logger = LoggerFactory.getLogger(GoogleService.class); - - @Value("${spring.security.oauth2.client.registration.google.client-id}") - private String clientId; - - @Value("${spring.security.oauth2.client.registration.google.client-secret}") - private String clientSecret; - - @Value("${spring.security.oauth2.client.registration.google.redirect-uri}") - private String redirectUri; - - @Value("${spring.security.oauth2.client.provider.google.token-uri}") - private String tokenUri; - - @Value("${spring.security.oauth2.client.provider.google.user-info-uri}") - private String userInfoUri; - - private final AuthenticationManager authenticationManager; - private final UserRepository userRepository; - private final JwtUtils jwtUtils; - private final PasswordEncoder oauth2PasswordEncoder; - - public GoogleService(AuthenticationManager authenticationManager, UserRepository userRepository, JwtUtils jwtUtils, PasswordEncoder oauth2PasswordEncoder) { - this.authenticationManager = authenticationManager; - this.userRepository = userRepository; - this.jwtUtils = jwtUtils; - this.oauth2PasswordEncoder = oauth2PasswordEncoder; - } - - public AuthResponseDto processGoogleCode(String code) { - try { - RestTemplate restTemplate = new RestTemplate(); - - HttpHeaders tokenHeaders = new HttpHeaders(); - tokenHeaders.set("Content-Type", "application/x-www-form-urlencoded"); - - MultiValueMap tokenRequestBody = new LinkedMultiValueMap<>(); - tokenRequestBody.add("client_id", clientId); - tokenRequestBody.add("client_secret", clientSecret); - tokenRequestBody.add("code", code); - tokenRequestBody.add("redirect_uri", redirectUri); - tokenRequestBody.add("grant_type", "authorization_code"); - - HttpEntity> tokenRequestEntity = new HttpEntity<>(tokenRequestBody, tokenHeaders); - - ResponseEntity tokenResponse = restTemplate.exchange( - tokenUri, - HttpMethod.POST, - tokenRequestEntity, - Map.class - ); - - Map tokenResponseBody = tokenResponse.getBody(); - - if (tokenResponseBody == null || tokenResponseBody.containsKey("error")) { - String error = tokenResponseBody != null ? (String) tokenResponseBody.get("error") : "Unknown error"; - throw new RuntimeException("Google OAuth error: " + error); - } - - String accessToken = (String) tokenResponseBody.get("access_token"); - if (accessToken == null || accessToken.isEmpty()) { - throw new RuntimeException("Failed to receive access token from Google"); - } - - HttpHeaders userInfoHeaders = new HttpHeaders(); - userInfoHeaders.set("Authorization", "Bearer " + accessToken); - - HttpEntity userInfoRequestEntity = new HttpEntity<>(null, userInfoHeaders); - - ResponseEntity userResponse = restTemplate.exchange( - userInfoUri, - HttpMethod.GET, - userInfoRequestEntity, - Map.class - ); - - Map userAttributes = userResponse.getBody(); - if (userAttributes == null) { - throw new RuntimeException("Failed to fetch user data from Google"); - } - - String googleId = (String) userAttributes.get("sub"); - String email = (String) userAttributes.get("email"); - String name = (String) userAttributes.get("name"); - Boolean emailVerified = (Boolean) userAttributes.getOrDefault("email_verified", false); - - if (email == null) { - throw new RuntimeException("Google account does not have an email"); - } - - String username = name != null ? name.replaceAll("\\s+", "") : email.split("@")[0]; - - Optional userOptional = userRepository.findByProviderId(googleId); - UserEntity user; - - if (userOptional.isPresent()) { - user = userOptional.get(); - } else { - userOptional = userRepository.findByEmail(email); - - if (userOptional.isPresent()) { - user = userOptional.get(); - user.setProvider(AuthProvider.GOOGLE); - user.setProviderId(googleId); - } else { - user = new UserEntity(); - user.setEmail(email); - user.setUsername(username); - user.setProvider(AuthProvider.GOOGLE); - user.setProviderId(googleId); - user.setEmailVerified(emailVerified); - - user.setBalance(new BigDecimal("100.00")); - } - } - - String randomPassword = UUID.randomUUID().toString(); - user.setPassword(oauth2PasswordEncoder.encode(randomPassword)); - - userRepository.save(user); - - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(user.getEmail(), randomPassword) - ); - - String token = jwtUtils.generateToken(authentication); - - return new AuthResponseDto(token); - - } catch (Exception e) { - logger.error("Failed to process Google authentication", e); - throw new RuntimeException("Failed to process Google authentication", e); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/service/AuthService.java b/backend/src/main/java/de/szut/casino/security/service/AuthService.java deleted file mode 100644 index 734cf9f..0000000 --- a/backend/src/main/java/de/szut/casino/security/service/AuthService.java +++ /dev/null @@ -1,108 +0,0 @@ -package de.szut.casino.security.service; - -import de.szut.casino.exceptionHandling.exceptions.EmailNotVerifiedException; -import de.szut.casino.security.dto.AuthResponseDto; -import de.szut.casino.security.dto.LoginRequestDto; -import de.szut.casino.security.dto.ResetPasswordDto; -import de.szut.casino.security.jwt.JwtUtils; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import de.szut.casino.user.dto.CreateUserDto; -import de.szut.casino.user.dto.GetUserDto; -import jakarta.mail.MessagingException; -import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.util.Optional; - -@Service -public class AuthService { - - private final AuthenticationManager authenticationManager; - private final JwtUtils jwtUtils; - private final UserService userService; - private final EmailService emailService; - private final PasswordEncoder passwordEncoder; - - public AuthService(AuthenticationManager authenticationManager, JwtUtils jwtUtils, UserService userService, EmailService emailService, PasswordEncoder passwordEncoder) { - this.authenticationManager = authenticationManager; - this.jwtUtils = jwtUtils; - this.userService = userService; - this.emailService = emailService; - this.passwordEncoder = passwordEncoder; - } - - public AuthResponseDto login(LoginRequestDto loginRequest) throws EmailNotVerifiedException { - if (!userService.isVerified(loginRequest.getUsernameOrEmail())) { - throw new EmailNotVerifiedException(); - } - - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken( - loginRequest.getUsernameOrEmail(), - loginRequest.getPassword())); - - SecurityContextHolder.getContext().setAuthentication(authentication); - String jwt = jwtUtils.generateToken(authentication); - - return new AuthResponseDto(jwt); - } - - public GetUserDto register(CreateUserDto signUpRequest) throws MessagingException, IOException { - UserEntity user = userService.createUser(signUpRequest); - - this.emailService.sendEmailVerificationEmail(user); - - return new GetUserDto( - user.getId(), - user.getEmail(), - user.getUsername(), - user.getBalance() - ); - } - - public Boolean verifyEmail(String token) throws MessagingException, IOException { - Optional optionalUser = userService.getUserByVerificationToken(token); - - if (!optionalUser.isPresent()) { - return false; - } - - UserEntity user = optionalUser.get(); - - user.setEmailVerified(true); - user.setVerificationToken(null); - userService.saveUser(user); - this.emailService.sendWelcomeEmail(user); - - return true; - } - - public void recoverPassword(String email) throws MessagingException, IOException { - Optional optionalUser = userService.getUserByEmail(email); - - if (optionalUser.isPresent()) { - UserEntity user = optionalUser.get(); - user.setPasswordResetToken(RandomStringUtils.randomAlphanumeric(64)); - userService.saveUser(user); - this.emailService.sendPasswordRecoveryEmail(user); - } - } - - public void resetPassword(ResetPasswordDto passwordDto) { - Optional optionalUser = userService.getUserByPasswordResetToken(passwordDto.getToken()); - - if (optionalUser.isPresent()) { - UserEntity user = optionalUser.get(); - user.setPassword(passwordEncoder.encode(passwordDto.getPassword())); - user.setPasswordResetToken(null); - userService.saveUser(user); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/service/EmailService.java b/backend/src/main/java/de/szut/casino/security/service/EmailService.java deleted file mode 100644 index 83d65e0..0000000 --- a/backend/src/main/java/de/szut/casino/security/service/EmailService.java +++ /dev/null @@ -1,115 +0,0 @@ -package de.szut.casino.security.service; - -import de.szut.casino.deposit.TransactionEntity; -import de.szut.casino.user.UserEntity; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ClassPathResource; -import org.springframework.mail.javamail.JavaMailSenderImpl; -import org.springframework.mail.javamail.MimeMessageHelper; -import org.springframework.stereotype.Service; -import org.springframework.util.FileCopyUtils; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; - -@Service -public class EmailService { - private JavaMailSenderImpl mailSender; - private MailConfig mailConfig; - @Value("${app.frontend-host}") - private String feUrl; - - public EmailService(JavaMailSenderImpl mailSender, MailConfig mailConfig) { - this.mailSender = mailSender; - this.mailConfig = mailConfig; - this.mailSender.setHost(mailConfig.host); - this.mailSender.setPort(mailConfig.port); - this.mailSender.setProtocol(mailConfig.protocol); - if (mailConfig.authenticationEnabled) { - this.mailSender.setUsername(mailConfig.username); - this.mailSender.setPassword(mailConfig.password); - } - } - - public void sendEmailVerificationEmail(UserEntity user) throws IOException, MessagingException { - String template = loadTemplate("email/verify.html"); - String htmlContent = template - .replace("${username}", user.getUsername()) - .replace("${feUrl}", feUrl) - .replace("${token}", user.getVerificationToken()); - - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - - helper.setFrom(mailConfig.fromAddress); - helper.setTo(user.getEmailAddress()); - helper.setSubject("E-Mail Bestätigung"); - helper.setText(htmlContent, true); - - mailSender.send(message); - } - - public void sendWelcomeEmail(UserEntity user) throws IOException, MessagingException { - String template = loadTemplate("email/welcome.html"); - String htmlContent = template - .replace("${username}", user.getUsername()) - .replace("${feUrl}", feUrl); - - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - - helper.setFrom(mailConfig.fromAddress); - helper.setTo(user.getEmailAddress()); - helper.setSubject("Willkommen bei Trustworthy Casino©"); - helper.setText(htmlContent, true); - - mailSender.send(message); - } - - public void sendDepositEmail(TransactionEntity transaction) throws IOException, MessagingException { - String template = loadTemplate("email/deposit.html"); - String htmlContent = template - .replace("${username}", transaction.getUser().getUsername()) - .replace("${amount}", String.valueOf(transaction.getAmount())) - .replace("${feUrl}", feUrl); - - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - - helper.setFrom(mailConfig.fromAddress); - helper.setTo(transaction.getUser().getEmailAddress()); - helper.setSubject("Einzahlung über ${amount}€ Erfolgreich".replace("${amount}", String.valueOf(transaction.getAmount()))); - helper.setText(htmlContent, true); - - mailSender.send(message); - } - - public void sendPasswordRecoveryEmail(UserEntity user) throws IOException, MessagingException { - String template = loadTemplate("email/recover-password.html"); - String htmlContent = template - .replace("${username}", user.getUsername()) - .replace("${resetToken}", user.getPasswordResetToken()) - .replace("${feUrl}", feUrl); - - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - - helper.setFrom(mailConfig.fromAddress); - helper.setTo(user.getEmailAddress()); - helper.setSubject("Zurücksetzen ihres Passworts"); - helper.setText(htmlContent, true); - - mailSender.send(message); - } - - private String loadTemplate(String templatePath) throws IOException { - ClassPathResource resource = new ClassPathResource("templates/" + templatePath); - try (Reader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) { - return FileCopyUtils.copyToString(reader); - } - } -} diff --git a/backend/src/main/java/de/szut/casino/security/service/MailConfig.java b/backend/src/main/java/de/szut/casino/security/service/MailConfig.java deleted file mode 100644 index 8a516fd..0000000 --- a/backend/src/main/java/de/szut/casino/security/service/MailConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.szut.casino.security.service; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -public class MailConfig { - @Value("${app.mail.host}") - public String host; - - @Value("${app.mail.port}") - public Integer port; - - @Value("${app.mail.authentication}") - public Boolean authenticationEnabled; - - @Value("${app.mail.username}") - public String username; - - @Value("${app.mail.password}") - public String password; - - @Value("${app.mail.from-address}") - public String fromAddress; - - @Value("${app.mail.protocol}") - public String protocol; -} diff --git a/backend/src/main/java/de/szut/casino/security/service/UserDetailsServiceImpl.java b/backend/src/main/java/de/szut/casino/security/service/UserDetailsServiceImpl.java deleted file mode 100644 index 2b710fc..0000000 --- a/backend/src/main/java/de/szut/casino/security/service/UserDetailsServiceImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.szut.casino.security.service; - -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.Optional; - -@Service -public class UserDetailsServiceImpl implements UserDetailsService { - - private final UserRepository userRepository; - - public UserDetailsServiceImpl(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Override - public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException { - Optional user = userRepository.findByUsername(usernameOrEmail); - - if (user.isEmpty()) { - user = userRepository.findByEmail(usernameOrEmail); - } - - UserEntity userEntity = user.orElseThrow(() -> - new UsernameNotFoundException("User not found with username or email: " + usernameOrEmail)); - - return new org.springframework.security.core.userdetails.User( - userEntity.getUsername(), - userEntity.getPassword(), - new ArrayList<>()); - } -} diff --git a/backend/src/main/java/de/szut/casino/shared/dto/BetDto.java b/backend/src/main/java/de/szut/casino/shared/dto/BetDto.java deleted file mode 100644 index cc00c2a..0000000 --- a/backend/src/main/java/de/szut/casino/shared/dto/BetDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.szut.casino.shared.dto; - -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class BetDto { - @NotNull(message = "Bet amount cannot be null") - @Positive(message = "Bet amount must be positive") - private BigDecimal betAmount; -} diff --git a/backend/src/main/java/de/szut/casino/shared/service/BalanceService.java b/backend/src/main/java/de/szut/casino/shared/service/BalanceService.java deleted file mode 100644 index 048840b..0000000 --- a/backend/src/main/java/de/szut/casino/shared/service/BalanceService.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.szut.casino.shared.service; - -import de.szut.casino.shared.dto.BetDto; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; - -@Service -public class BalanceService { - private final UserRepository userRepository; - - public BalanceService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public boolean hasFunds(UserEntity user, BetDto betDto) { - BigDecimal balance = user.getBalance(); - BigDecimal betAmount = betDto.getBetAmount(); - - return betAmount.compareTo(balance) <= 0; - } - - public void addFunds(UserEntity user, BigDecimal amount) { - user.addBalance(amount); - - this.userRepository.save(user); - } - - public void subtractFunds(UserEntity user, BigDecimal amount) { - user.subtractBalance(amount); - - this.userRepository.save(user); - } -} diff --git a/backend/src/main/java/de/szut/casino/slots/SlotController.java b/backend/src/main/java/de/szut/casino/slots/SlotController.java deleted file mode 100644 index ff29d3d..0000000 --- a/backend/src/main/java/de/szut/casino/slots/SlotController.java +++ /dev/null @@ -1,59 +0,0 @@ -package de.szut.casino.slots; - -import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException; -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import de.szut.casino.shared.dto.BetDto; -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import jakarta.validation.Valid; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -@RestController -public class SlotController { - private final UserService userService; - private final BalanceService balanceService; - private final SlotService slotService; - - public SlotController(UserService userService, BalanceService balanceService, SlotService slotService) { - this.userService = userService; - this.balanceService = balanceService; - this.slotService = slotService; - } - - @PostMapping("/slots/spin") - public ResponseEntity spinSlots(@RequestBody @Valid BetDto betDto) { - UserEntity user = userService.getCurrentUser(); - - if (!this.balanceService.hasFunds(user, betDto)) { - throw new InsufficientFundsException(); - } - - SpinResult spinResult = this.slotService.spin( - betDto.getBetAmount(), - user - ); - - return ResponseEntity.ok(spinResult); - } - - @GetMapping("/slots/info") - public ResponseEntity spinSlots() { - Map info = new HashMap<>(); - - for (Symbol symbol : Symbol.values()) { - info.put(symbol.getDisplayName(), symbol.getPayoutMultiplier()); - } - - return ResponseEntity.ok(info); - } -} diff --git a/backend/src/main/java/de/szut/casino/slots/SlotService.java b/backend/src/main/java/de/szut/casino/slots/SlotService.java deleted file mode 100644 index 7905636..0000000 --- a/backend/src/main/java/de/szut/casino/slots/SlotService.java +++ /dev/null @@ -1,137 +0,0 @@ -package de.szut.casino.slots; - -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import static de.szut.casino.slots.Symbol.*; - -@Service -public class SlotService { - private final int REEL_LENGTH = 32; - - private final List firstReel; - private final List secondReel; - private final List thirdReel; - - private final Random random; - private final BalanceService balanceService; - - public SlotService(BalanceService balanceService) { - this.random = new Random(); - this.balanceService = balanceService; - - List reelStrip = createReelStrip(); - this.firstReel = shuffleReel(reelStrip); - this.secondReel = shuffleReel(reelStrip); - this.thirdReel = shuffleReel(reelStrip); - } - - public SpinResult spin(BigDecimal betAmount, UserEntity user) { - int index1 = this.random.nextInt(REEL_LENGTH); - int index2 = this.random.nextInt(REEL_LENGTH); - int index3 = this.random.nextInt(REEL_LENGTH); - - Symbol symbol1 = getSymbolAt(this.firstReel, index1); - Symbol symbol2 = getSymbolAt(this.secondReel, index2); - Symbol symbol3 = getSymbolAt(this.thirdReel, index3); - - Status status = determineStatus(symbol1, symbol2, symbol3); - - SpinResult spinResult = processResult(betAmount, user, status, symbol1); - buildResultMatrix(spinResult, index1, index2, index3); - - return spinResult; - } - - private SpinResult processResult(BigDecimal betAmount, UserEntity user, Status status, Symbol winSymbol) { - SpinResult spinResult = new SpinResult(); - spinResult.setStatus(status.name().toLowerCase()); - - this.balanceService.subtractFunds(user, betAmount); - - if (status == Status.WIN) { - BigDecimal winAmount = betAmount.multiply(winSymbol.getPayoutMultiplier()); - this.balanceService.addFunds(user, winAmount); - spinResult.setAmount(winAmount); - } else { - spinResult.setAmount(betAmount); - } - - return spinResult; - } - - private void buildResultMatrix(SpinResult spinResult, int index1, int index2, int index3) { - List> resultMatrix = new ArrayList<>(3); - - for (int i = 0; i < 3; i++) { - resultMatrix.add(new ArrayList<>(3)); - } - - resultMatrix.getFirst().add(getSymbolAt(this.firstReel, index1 - 1)); - resultMatrix.getFirst().add(getSymbolAt(this.secondReel, index2 - 1)); - resultMatrix.getFirst().add(getSymbolAt(this.thirdReel, index3 - 1)); - - resultMatrix.get(1).add(getSymbolAt(this.firstReel, index1)); - resultMatrix.get(1).add(getSymbolAt(this.secondReel, index2)); - resultMatrix.get(1).add(getSymbolAt(this.thirdReel, index3)); - - resultMatrix.getLast().add(getSymbolAt(this.firstReel, index1 + 1)); - resultMatrix.getLast().add(getSymbolAt(this.secondReel, index2 + 1)); - resultMatrix.getLast().add(getSymbolAt(this.thirdReel, index3 + 1)); - - spinResult.setResultMatrix(resultMatrix); - } - - private List shuffleReel(List reelStrip) { - Collections.shuffle(reelStrip, this.random); - - return reelStrip; - } - - private List createReelStrip() { - List reelStrip = new ArrayList<>(REEL_LENGTH); - addSymbolsToStrip(reelStrip, CHERRY, CHERRY.getCountPerStrip()); - addSymbolsToStrip(reelStrip, BELL, BELL.getCountPerStrip()); - addSymbolsToStrip(reelStrip, BAR, BAR.getCountPerStrip()); - addSymbolsToStrip(reelStrip, SEVEN, SEVEN.getCountPerStrip()); - addSymbolsToStrip(reelStrip, BLANK, BLANK.getCountPerStrip()); - return reelStrip; - } - - private void addSymbolsToStrip(List strip, Symbol symbol, int count) { - for (int i = 0; i < count; i++) { - strip.add(symbol); - } - } - - private Symbol getSymbolAt(List reel, int index) { - int effectiveIndex = index % REEL_LENGTH; - - if (effectiveIndex < 0) { - effectiveIndex += REEL_LENGTH; - } - - return reel.get(effectiveIndex); - } - - private Status determineStatus(Symbol symbol1, Symbol symbol2, Symbol symbol3) { - boolean allSymbolsMatch = symbol1.equals(symbol2) && symbol1.equals(symbol3); - - if (allSymbolsMatch) { - if (symbol1 == Symbol.BLANK) { - return Status.BLANK; - } else { - return Status.WIN; - } - } - - return Status.LOSE; - } -} diff --git a/backend/src/main/java/de/szut/casino/slots/SpinResult.java b/backend/src/main/java/de/szut/casino/slots/SpinResult.java deleted file mode 100644 index 0bfb317..0000000 --- a/backend/src/main/java/de/szut/casino/slots/SpinResult.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.szut.casino.slots; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; -import java.util.List; - -@Getter -@Setter -@NoArgsConstructor -public class SpinResult { - private String status; - private BigDecimal amount; - private List> resultMatrix; -} diff --git a/backend/src/main/java/de/szut/casino/slots/Status.java b/backend/src/main/java/de/szut/casino/slots/Status.java deleted file mode 100644 index c53611f..0000000 --- a/backend/src/main/java/de/szut/casino/slots/Status.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.szut.casino.slots; - -public enum Status { - WIN, - LOSE, - BLANK -} diff --git a/backend/src/main/java/de/szut/casino/slots/Symbol.java b/backend/src/main/java/de/szut/casino/slots/Symbol.java deleted file mode 100644 index 3cf0f72..0000000 --- a/backend/src/main/java/de/szut/casino/slots/Symbol.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.szut.casino.slots; - -import lombok.Getter; - -import java.math.BigDecimal; - -@Getter -public enum Symbol { - SEVEN("seven", new BigDecimal("1000"), 1), - BAR("bar", new BigDecimal("85"), 4), - BELL("bell", new BigDecimal("40"), 7), - CHERRY("cherry", new BigDecimal("10"), 10), - BLANK("blank", new BigDecimal("0"), 10); - - private final String displayName; - private final BigDecimal payoutMultiplier; - private final int countPerStrip; - - Symbol(String displayName, BigDecimal payoutMultiplier, int count) { - this.displayName = displayName; - this.payoutMultiplier = payoutMultiplier; - this.countPerStrip = count; - } -} diff --git a/backend/src/main/java/de/szut/casino/user/AuthProvider.java b/backend/src/main/java/de/szut/casino/user/AuthProvider.java deleted file mode 100644 index c26b45c..0000000 --- a/backend/src/main/java/de/szut/casino/user/AuthProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.szut.casino.user; - -public enum AuthProvider { - LOCAL, - GITHUB, - GOOGLE -} diff --git a/backend/src/main/java/de/szut/casino/user/UserController.java b/backend/src/main/java/de/szut/casino/user/UserController.java deleted file mode 100644 index f08721d..0000000 --- a/backend/src/main/java/de/szut/casino/user/UserController.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.szut.casino.user; - -import de.szut.casino.user.dto.GetUserDto; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Slf4j -@RestController -@CrossOrigin -@RequestMapping("/users") -public class UserController { - - private final UserService userService; - - private final UserMappingService userMappingService; - - public UserController(UserService userService, UserMappingService userMappingService) { - this.userService = userService; - this.userMappingService = userMappingService; - } - - @GetMapping("/me") - public ResponseEntity getCurrentUser() { - return ResponseEntity.ok(userMappingService.mapToGetUserDto(userService.getCurrentUser())); - } -} diff --git a/backend/src/main/java/de/szut/casino/user/UserEntity.java b/backend/src/main/java/de/szut/casino/user/UserEntity.java deleted file mode 100644 index 534859f..0000000 --- a/backend/src/main/java/de/szut/casino/user/UserEntity.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.szut.casino.user; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Setter -@Getter -@Entity -@NoArgsConstructor -public class UserEntity { - @Id - @GeneratedValue - private Long id; - - @Version - private Long version; - - @Column(unique = true) - private String email; - - @Column(unique = true) - private String username; - - private String password; - - @Column(precision = 19, scale = 2) - private BigDecimal balance; - - private Boolean emailVerified = false; - - private String verificationToken; - - private String passwordResetToken; - - @Enumerated(EnumType.STRING) - private AuthProvider provider = AuthProvider.LOCAL; - - private String providerId; - - public UserEntity(String email, String username, String password, BigDecimal balance, String verificationToken) { - this.email = email; - this.username = username; - this.password = password; - this.balance = balance; - this.verificationToken = verificationToken; - } - - public UserEntity(String email, String username, AuthProvider provider, String providerId, BigDecimal balance) { - this.email = email; - this.username = username; - this.provider = provider; - this.providerId = providerId; - this.balance = balance; - this.emailVerified = true; // OAuth providers verify emails - } - - public void addBalance(BigDecimal amountToAdd) { - if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) <= 0) { - return; - } - - if (this.balance == null) { - this.balance = BigDecimal.ZERO; - } - - this.balance = this.balance.add(amountToAdd); - } - - public void subtractBalance(BigDecimal amountToSubtract) { - if (amountToSubtract == null || amountToSubtract.compareTo(BigDecimal.ZERO) <= 0) { - throw new IllegalArgumentException("Amount to subtract must be positive."); - } - - if (this.balance == null) { - this.balance = BigDecimal.ZERO; - } - - if (this.balance.compareTo(amountToSubtract) < 0) { - throw new IllegalStateException("Insufficient funds to subtract " + amountToSubtract); - } - - this.balance = this.balance.subtract(amountToSubtract); - } - - public String getEmailAddress() { - return "${name} <${email}>".replace("${name}", this.username).replace("${email}", this.email); - } -} diff --git a/backend/src/main/java/de/szut/casino/user/UserMappingService.java b/backend/src/main/java/de/szut/casino/user/UserMappingService.java deleted file mode 100644 index c93c132..0000000 --- a/backend/src/main/java/de/szut/casino/user/UserMappingService.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.szut.casino.user; - -import de.szut.casino.user.dto.GetUserDto; -import org.springframework.stereotype.Service; - -@Service -public class UserMappingService { - - public GetUserDto mapToGetUserDto(UserEntity user) { - return new GetUserDto(user.getId(), user.getEmail(), user.getUsername(), user.getBalance()); - } -} - diff --git a/backend/src/main/java/de/szut/casino/user/UserRepository.java b/backend/src/main/java/de/szut/casino/user/UserRepository.java deleted file mode 100644 index db28f49..0000000 --- a/backend/src/main/java/de/szut/casino/user/UserRepository.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.szut.casino.user; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -@Service -public interface UserRepository extends JpaRepository { - Optional findByUsername(String username); - - Optional findByEmail(String email); - - Optional findByProviderId(String providerId); - - boolean existsByUsername(String username); - - boolean existsByEmail(String email); - - @Query("SELECT u FROM UserEntity u WHERE u.verificationToken = ?1") - Optional findOneByVerificationToken(String token); - - @Query("SELECT u FROM UserEntity u WHERE u.username = ?1 OR u.email = ?1") - Optional findOneByUsernameOrEmail(String usernameOrEmail); - - @Query("SELECT u FROM UserEntity u WHERE u.passwordResetToken = ?1") - Optional findOneByPasswordResetToken(String token); -} diff --git a/backend/src/main/java/de/szut/casino/user/UserService.java b/backend/src/main/java/de/szut/casino/user/UserService.java deleted file mode 100644 index 341db86..0000000 --- a/backend/src/main/java/de/szut/casino/user/UserService.java +++ /dev/null @@ -1,80 +0,0 @@ -package de.szut.casino.user; - -import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException; -import de.szut.casino.user.dto.CreateUserDto; -import jakarta.persistence.EntityExistsException; -import org.apache.commons.lang3.RandomStringUtils; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.Optional; - -@Service -public class UserService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - - public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { - this.userRepository = userRepository; - this.passwordEncoder = passwordEncoder; - } - - public UserEntity createUser(CreateUserDto createUserDto) { - if (userRepository.existsByUsername(createUserDto.getUsername())) { - throw new EntityExistsException("Username is already taken"); - } - - if (userRepository.existsByEmail(createUserDto.getEmail())) { - throw new EntityExistsException("Email is already in use"); - } - - UserEntity user = new UserEntity( - createUserDto.getEmail(), - createUserDto.getUsername(), - passwordEncoder.encode(createUserDto.getPassword()), - BigDecimal.valueOf(100), - RandomStringUtils.randomAlphanumeric(64) - ); - - return userRepository.save(user); - } - - public UserEntity getCurrentUser() { - String username = SecurityContextHolder.getContext().getAuthentication().getName(); - - Optional optionalUser = userRepository.findByUsername(username); - if (optionalUser.isEmpty()) { - throw new UserNotFoundException(); - } - - return optionalUser.get(); - } - - public Optional getUserByVerificationToken(String token) { - return this.userRepository.findOneByVerificationToken(token); - } - - public void saveUser(UserEntity user) { - userRepository.save(user); - } - - public boolean isVerified(String usernameOrEmail) { - Optional optionalUser = userRepository.findOneByUsernameOrEmail(usernameOrEmail); - - if (!optionalUser.isPresent()) { - return false; - } - - return optionalUser.get().getEmailVerified(); - } - - public Optional getUserByEmail(String email) { - return userRepository.findByEmail(email); - } - - public Optional getUserByPasswordResetToken(String token) { - return this.userRepository.findOneByPasswordResetToken(token); - } -} diff --git a/backend/src/main/java/de/szut/casino/user/dto/CreateUserDto.java b/backend/src/main/java/de/szut/casino/user/dto/CreateUserDto.java deleted file mode 100644 index 1be6ae3..0000000 --- a/backend/src/main/java/de/szut/casino/user/dto/CreateUserDto.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.szut.casino.user.dto; - -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class CreateUserDto { - @NotBlank(message = "Email is required") - @Email(message = "Email should be valid") - private String email; - - @NotBlank(message = "Username is required") - @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters") - private String username; - - @NotBlank(message = "Password is required") - @Size(min = 6, message = "Password must be at least 6 characters") - private String password; -} diff --git a/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java b/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java deleted file mode 100644 index 2c41f0d..0000000 --- a/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.szut.casino.user.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.math.BigDecimal; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class GetUserDto { - private Long id; - private String email; - private String username; - private BigDecimal balance; -} diff --git a/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java b/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java deleted file mode 100644 index 11fff4f..0000000 --- a/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.szut.casino.user.transaction; - -import de.szut.casino.deposit.TransactionEntity; -import de.szut.casino.deposit.TransactionRepository; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserService; -import de.szut.casino.user.transaction.dto.GetTransactionDto; -import de.szut.casino.user.transaction.dto.UserTransactionsDto; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class GetTransactionService { - - private final UserService userService; - - private final TransactionRepository transactionRepository; - - public GetTransactionService(UserService userService, TransactionRepository transactionRepository) { - this.userService = userService; - this.transactionRepository = transactionRepository; - } - - public UserTransactionsDto getUserTransactionsDto(Integer limit, Integer offset) { - UserEntity user = userService.getCurrentUser(); - - List transactionEntities = this.transactionRepository.findByUserIdWithLimit(user, limit, offset); - Boolean hasMore = this.transactionRepository.hasMore(user, limit, offset); - - return new UserTransactionsDto(mapTransactionsToDtos(transactionEntities), hasMore); - } - - public List mapTransactionsToDtos(List transactions) { - return transactions.stream() - .map(transaction -> new GetTransactionDto( - transaction.getAmount(), - transaction.getStatus(), - transaction.getCreatedAt()) - ).toList(); - } -} - diff --git a/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java b/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java deleted file mode 100644 index f8a57de..0000000 --- a/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.szut.casino.user.transaction; - -import de.szut.casino.user.transaction.dto.UserTransactionsDto; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class TransactionController { - - private final GetTransactionService transactionService; - - public TransactionController(GetTransactionService transactionService) { - this.transactionService = transactionService; - } - - @GetMapping("/user/transactions") - public ResponseEntity getUserTransactions( - @RequestParam(value = "limit", required = false) Integer limit, - @RequestParam(value = "offset", required = false) Integer offset - ) { - UserTransactionsDto transactionEntities = this.transactionService.getUserTransactionsDto(limit, offset); - - return ResponseEntity.ok(transactionEntities); - } -} - diff --git a/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java b/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java deleted file mode 100644 index f37fbf4..0000000 --- a/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package de.szut.casino.user.transaction.dto; - -import de.szut.casino.deposit.TransactionStatus; -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; - -import java.util.Date; - -@AllArgsConstructor -@NoArgsConstructor -public class GetTransactionDto { - public double amount = 0; - public TransactionStatus status = TransactionStatus.PROCESSING; - public Date createdAt = new Date(); -} - diff --git a/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java b/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java deleted file mode 100644 index 54e116b..0000000 --- a/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.szut.casino.user.transaction.dto; - -import lombok.AllArgsConstructor; - -import java.util.List; - -@AllArgsConstructor -public class UserTransactionsDto { - public List transactions; - public Boolean hasMore; -} - diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties deleted file mode 100644 index 7b761a7..0000000 --- a/backend/src/main/resources/application.properties +++ /dev/null @@ -1,54 +0,0 @@ -spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:postgresdb} -spring.datasource.username=${DB_USER:postgres_user} -spring.datasource.password=${DB_PASS:postgres_pass} -server.port=${HTTP_PORT:8080} -spring.jpa.hibernate.ddl-auto=update -stripe.secret.key=${STRIPE_SECRET_KEY:sk_test_51QrePYIvCfqz7ANgqam8rEwWcMeKiLOof3j6SCMgu2sl4sESP45DJxca16mWcYo1sQaiBv32CMR6Z4AAAGQPCJo300ubuZKO8I} -stripe.webhook.secret=${STRIPE_WEBHOOK_SECRET:whsec_746b6a488665f6057118bdb4a2b32f4916f16c277109eeaed5e8f8e8b81b8c15} - -app.frontend-host=${FE_URL:http://localhost:4200} - -app.mail.authentication=${MAIL_AUTHENTICATION:false} -app.mail.host=${MAIL_HOST:localhost} -app.mail.port=${MAIL_PORT:1025} -app.mail.username=${MAIL_USER:null} -app.mail.password=${MAIL_PASS:null} -app.mail.from-address=${MAIL_FROM:casino@localhost} -app.mail.protocol=${MAIL_PROTOCOL:smtp} - -spring.application.name=casino - -# JWT Configuration -jwt.secret=${JWT_SECRET:5367566B59703373367639792F423F4528482B4D6251655468576D5A71347437} -jwt.expiration.ms=${JWT_EXPIRATION_MS:86400000} - -# Logging -logging.level.org.springframework.security=DEBUG - -# Swagger -springdoc.swagger-ui.path=swagger -springdoc.swagger-ui.try-it-out-enabled=true - -# GitHub OAuth2 Configuration -spring.security.oauth2.client.registration.github.client-id=${GITHUB_CLIENT_ID:Ov23lingzZsPn1wwACoK} -spring.security.oauth2.client.registration.github.client-secret=${GITHUB_CLIENT_SECRET:4b327fb3b1ab67584a03bcb9d53fa6439fbccad7} -spring.security.oauth2.client.registration.github.redirect-uri=${app.frontend-host}/oauth2/callback/github -spring.security.oauth2.client.registration.github.scope=user:email,read:user -spring.security.oauth2.client.provider.github.authorization-uri=https://github.com/login/oauth/authorize -spring.security.oauth2.client.provider.github.token-uri=https://github.com/login/oauth/access_token -spring.security.oauth2.client.provider.github.user-info-uri=https://api.github.com/user -spring.security.oauth2.client.provider.github.user-name-attribute=login - -# OAuth Success and Failure URLs -app.oauth2.authorizedRedirectUris=${app.frontend-host}/auth/oauth2/callback - -# Google OAuth2 Configuration -spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID:350791038883-c1r7v4o793itq8a0rh7dut7itm7uneam.apps.googleusercontent.com} -spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET: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} -spring.security.oauth2.client.registration.google.redirect-uri=${app.frontend-host}/oauth2/callback/google -spring.security.oauth2.client.registration.google.scope=email,profile -spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth -spring.security.oauth2.client.provider.google.token-uri=https://oauth2.googleapis.com/token -spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo -spring.security.oauth2.client.provider.google.user-name-attribute=sub - diff --git a/backend/src/main/resources/templates/email/deposit.html b/backend/src/main/resources/templates/email/deposit.html deleted file mode 100644 index be54677..0000000 --- a/backend/src/main/resources/templates/email/deposit.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - Einzahlung bestätigt - Trustworthy Casino© - - - -
-
-

Trustworthy Casino

-
-
-

Hallo ${username},

- -

vielen Dank für Ihre Einzahlung bei Trustworthy Casino. Wir bestätigen den Eingang Ihres Guthabens.

- -
-

Eingezahlter Betrag

-
${amount}€
-
- -
- -

Ihr Guthaben wurde Ihrem Konto sofort gutgeschrieben und steht ab sofort zum Spielen zur Verfügung.

- - - -

Bei Fragen zu Ihrer Einzahlung kontaktieren Sie bitte unseren Kundenservice.

- -

Mit freundlichen Grüßen,
- Ihr Trustworthy Casino Team

-
- -
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/email/recover-password.html b/backend/src/main/resources/templates/email/recover-password.html deleted file mode 100644 index cf666d1..0000000 --- a/backend/src/main/resources/templates/email/recover-password.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - Passwort zurücksetzen - Trustworthy Casino© - - - -
-
-

Trustworthy Casino

-
-
-

Hallo ${username},

- -

wir haben eine Anfrage zum Zurücksetzen Ihres Passworts für Ihr Trustworthy Casino Konto erhalten. Um Ihr Passwort zurückzusetzen, klicken Sie bitte auf den folgenden Button:

- - - -
-

Hinweis: Dieser Link und Code sind aus Sicherheitsgründen vielleicht nur 60 Minuten gültig.

-
- -
- -
-

Falls Sie diese Anfrage nicht gestellt haben, ignorieren Sie diese E-Mail bitte. In diesem Fall empfehlen wir Ihnen, Ihr Passwort zu ändern und unseren Kundenservice zu kontaktieren, um die Sicherheit Ihres Kontos zu gewährleisten.

-
- -
- -

Bei Fragen steht Ihnen unser Support-Team nicht zur Verfügung.

- -

Mit freundlichen Grüßen,
- Ihr Trustworthy Casino Team

-
- -
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/email/verify.html b/backend/src/main/resources/templates/email/verify.html deleted file mode 100644 index 7076a7c..0000000 --- a/backend/src/main/resources/templates/email/verify.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - E-Mail-Verifizierung - Trustworthy Casino© - - - -
-
-

Trustworthy Casino

-
-
-

Hallo ${username},

- -

vielen Dank für Ihre Registrierung bei Trustworthy Casino. Um Ihr Konto zu aktivieren und Zugang zu allen Funktionen zu erhalten, bestätigen Sie bitte Ihre E-Mail-Adresse.

- -
- -

Klicken Sie auf den folgenden Button, um Ihre E-Mail-Adresse zu bestätigen:

- - - -
-

Hinweis: Der Bestätigungscode könnte nur 24 Stunden gültig sein und kann vielleicht auch nur einmal verwendet werden.

-
- -
- -

Nach der Bestätigung Ihrer E-Mail-Adresse können Sie sofort mit dem Spielen beginnen und alle Vorteile Ihres Kontos nutzen.

- -

Bei Fragen stehen wir Ihnen jederzeit zur Verfügung.

- -

Mit freundlichen Grüßen,
- Ihr Trustworthy Casino Team

-
- -
- - \ No newline at end of file diff --git a/backend/src/main/resources/templates/email/welcome.html b/backend/src/main/resources/templates/email/welcome.html deleted file mode 100644 index ed43938..0000000 --- a/backend/src/main/resources/templates/email/welcome.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - Willkommen bei Trustworthy Casino© - - - -
-
-

Trustworthy Casino

-
-
-

Hallo ${username},

- -

Herzlich willkommen bei Trustworthy Casino! Wir freuen uns, Sie an Bord zu haben.

- -
- -

Bei uns erwarten Sie:

-
    -
  • Spannende Casino-Spiele
  • -
  • Sichere Transaktionen
  • -
  • Exklusive Boni und Aktionen
  • -
- -
- -

Melden Sie sich jetzt an und beginnen Sie Ihr Spielerlebnis!

- - - -

Bei Fragen stehen wir Ihnen jederzeit zur Verfügung.

- -

Mit freundlichen Grüßen,
- Ihr Trustworthy Casino Team

-
- -
- - \ No newline at end of file diff --git a/backend/src/test/java/de/szut/casino/coinflip/CoinflipServiceTest.java b/backend/src/test/java/de/szut/casino/coinflip/CoinflipServiceTest.java deleted file mode 100644 index 2b15ba0..0000000 --- a/backend/src/test/java/de/szut/casino/coinflip/CoinflipServiceTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.szut.casino.coinflip; - -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.math.BigDecimal; -import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class CoinflipServiceTest { - - @Mock - private BalanceService balanceService; - - @Mock - private Random random; - - @InjectMocks - private CoinflipService coinflipService; - - private UserEntity user; - private CoinflipDto coinflipDto; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - user = new UserEntity(); - user.setBalance(BigDecimal.valueOf(100)); - coinflipDto = new CoinflipDto(BigDecimal.valueOf(10), CoinSide.HEAD); - } - - @Test - void testPlay_userWins() { - when(random.nextBoolean()).thenReturn(true); - - CoinflipResult result = coinflipService.play(user, coinflipDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(20), result.getPayout()); - assertEquals(CoinSide.HEAD, result.getCoinSide()); - verify(balanceService, times(1)).subtractFunds(user, BigDecimal.valueOf(10)); - verify(balanceService, times(1)).addFunds(user, BigDecimal.valueOf(20)); - } - - @Test - void testPlay_userLoses() { - when(random.nextBoolean()).thenReturn(false); - - CoinflipResult result = coinflipService.play(user, coinflipDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - assertEquals(CoinSide.TAILS, result.getCoinSide()); - verify(balanceService, times(1)).subtractFunds(user, BigDecimal.valueOf(10)); - verify(balanceService, never()).addFunds(any(), any()); - } -} diff --git a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java b/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java deleted file mode 100644 index 6b2e230..0000000 --- a/backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java +++ /dev/null @@ -1,251 +0,0 @@ -package de.szut.casino.dice; - -import de.szut.casino.shared.service.BalanceService; -import de.szut.casino.user.UserEntity; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class DiceServiceTest { - - @Mock - private BalanceService balanceService; - - @Mock - private Random random; - - @InjectMocks - private DiceService diceService; - - private UserEntity user; - private DiceDto diceDto; - - @BeforeEach - void setUp() { - user = new UserEntity(); - user.setId(1L); - user.setBalance(BigDecimal.valueOf(1000)); - - diceDto = new DiceDto(); - diceDto.setBetAmount(BigDecimal.valueOf(10)); - diceDto.setTargetValue(BigDecimal.valueOf(50)); - diceDto.setRollOver(true); - } - - @Test - void play_rollOver_win() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(50)); - when(random.nextInt(anyInt())).thenReturn(55); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(56), result.getRolledValue()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollOver_lose() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(50)); - when(random.nextInt(anyInt())).thenReturn(49); - - DiceResult result = diceService.play(user, diceDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.valueOf(50), result.getRolledValue()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollUnder_win() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(50)); - when(random.nextInt(anyInt())).thenReturn(48); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(49), result.getRolledValue()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollUnder_lose() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(50)); - when(random.nextInt(anyInt())).thenReturn(50); - - DiceResult result = diceService.play(user, diceDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.valueOf(51), result.getRolledValue()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollOver_targetValueOne_rolledOne_lose() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(1)); - when(random.nextInt(anyInt())).thenReturn(0); - - DiceResult result = diceService.play(user, diceDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.valueOf(1), result.getRolledValue()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollOver_targetValueOne_rolledTwo_win() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(1)); - when(random.nextInt(anyInt())).thenReturn(1); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(2), result.getRolledValue()); - // Win chance for target 1 (roll over) is 99. Multiplier = (100-1)/99 = 1 - assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollUnder_targetValueOne_alwaysLose_winChanceZero() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(1)); - when(random.nextInt(anyInt())).thenReturn(0); - - DiceResult result = diceService.play(user, diceDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.valueOf(1), result.getRolledValue()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollOver_targetValueNinetyNine_rolledHundred_win() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(99)); - when(random.nextInt(anyInt())).thenReturn(99); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(100), result.getRolledValue()); - // Win chance for target 99 (roll over) is 1. Multiplier = (100-1)/1 = 99 - assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99)).stripTrailingZeros(), result.getPayout().stripTrailingZeros()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollUnder_targetValueNinetyNine_rolledNinetyEight_win() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(99)); - when(random.nextInt(anyInt())).thenReturn(97); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(98), result.getRolledValue()); - // Win chance for target 99 (roll under) is 98. Multiplier = (100-1)/98 = 99/98 - assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99).divide(BigDecimal.valueOf(98), 4, RoundingMode.HALF_UP)), result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollOver_targetValueOneHundred_alwaysLose_winChanceZero() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(100)); - when(random.nextInt(anyInt())).thenReturn(99); - - DiceResult result = diceService.play(user, diceDto); - - assertFalse(result.isWin()); - assertEquals(BigDecimal.valueOf(100), result.getRolledValue()); - assertEquals(BigDecimal.ZERO, result.getPayout()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_rollUnder_targetValueOneHundred_rolledNinetyNine_win() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(100)); - when(random.nextInt(anyInt())).thenReturn(98); - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(99), result.getRolledValue()); - // Win chance for target 100 (roll under) is 99. Multiplier = (100-1)/99 = 1 - assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros()); - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class)); - } - - @Test - void play_payoutCalculationCorrect() { - diceDto.setRollOver(true); - diceDto.setTargetValue(BigDecimal.valueOf(75)); - when(random.nextInt(anyInt())).thenReturn(75); - - // Multiplier for win chance 25: (100-1)/25 = 99/25 = 3.96 - // Payout: 10 * 3.96 = 39.6 - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(39.6).stripTrailingZeros(), result.getPayout().stripTrailingZeros()); - } - - @Test - void play_payoutCalculationCorrect_rollUnder() { - diceDto.setRollOver(false); - diceDto.setTargetValue(BigDecimal.valueOf(25)); - when(random.nextInt(anyInt())).thenReturn(0); - - // Multiplier for win chance 24: (100-1)/24 = 99/24 = 4.125 - // Payout: 10 * 4.125 = 41.25 - - DiceResult result = diceService.play(user, diceDto); - - assertTrue(result.isWin()); - assertEquals(BigDecimal.valueOf(41.25).stripTrailingZeros(), result.getPayout().stripTrailingZeros()); - } - - @Test - void play_betAmountSubtracted() { - when(random.nextInt(anyInt())).thenReturn(50); - - diceService.play(user, diceDto); - - verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount()); - } -} diff --git a/backend/src/test/java/de/szut/casino/shared/service/BalanceServiceTest.java b/backend/src/test/java/de/szut/casino/shared/service/BalanceServiceTest.java deleted file mode 100644 index dfb96e5..0000000 --- a/backend/src/test/java/de/szut/casino/shared/service/BalanceServiceTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.szut.casino.shared.service; - -import de.szut.casino.shared.dto.BetDto; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.math.BigDecimal; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class BalanceServiceTest { - - @Mock - private UserRepository userRepository; - - @InjectMocks - private BalanceService balanceService; - - private UserEntity user; - private BetDto betDto; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - user = new UserEntity(); - user.setBalance(BigDecimal.valueOf(100)); - betDto = new BetDto(); - } - - @Test - void testHasFunds_sufficientFunds() { - betDto.setBetAmount(BigDecimal.valueOf(50)); - assertTrue(balanceService.hasFunds(user, betDto)); - } - - @Test - void testHasFunds_insufficientFunds() { - betDto.setBetAmount(BigDecimal.valueOf(150)); - assertFalse(balanceService.hasFunds(user, betDto)); - } - - @Test - void testHasFunds_exactFunds() { - betDto.setBetAmount(BigDecimal.valueOf(100)); - assertTrue(balanceService.hasFunds(user, betDto)); - } - - @Test - void testAddFunds() { - BigDecimal amountToAdd = BigDecimal.valueOf(50); - balanceService.addFunds(user, amountToAdd); - assertEquals(BigDecimal.valueOf(150), user.getBalance()); - verify(userRepository, times(1)).save(user); - } - - @Test - void testSubtractFunds_sufficientFunds() { - BigDecimal amountToSubtract = BigDecimal.valueOf(50); - balanceService.subtractFunds(user, amountToSubtract); - assertEquals(BigDecimal.valueOf(50), user.getBalance()); - verify(userRepository, times(1)).save(user); - } - - @Test - void testSubtractFunds_insufficientFunds() { - BigDecimal amountToSubtract = BigDecimal.valueOf(150); - assertThrows(IllegalStateException.class, () -> balanceService.subtractFunds(user, amountToSubtract)); - verify(userRepository, never()).save(user); - } -} diff --git a/compose.yml b/compose.yml deleted file mode 100644 index d3c7a87..0000000 --- a/compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -volumes: - postgres_data: - -services: - db: - image: postgres:17.5 - container_name: casino-db - restart: unless-stopped - volumes: - - postgres_data:/var/lib/postgresql/data - environment: - POSTGRES_DB: postgresdb - POSTGRES_USER: postgres_user - POSTGRES_PASSWORD: postgres_pass - healthcheck: - test: "exit 0" - ports: - - "5432:5432" - mailpit: - image: axllent/mailpit - container_name: casino-mailpit - restart: unless-stopped - ports: - - 8025:8025 - - 1025:1025 - environment: - MP_SMTP_AUTH_ACCEPT_ANY: 1 - MP_SMTP_AUTH_ALLOW_INSECURE: 1 diff --git a/frontend/.docker/Dockerfile b/frontend/.docker/Dockerfile deleted file mode 100644 index 45a769c..0000000 --- a/frontend/.docker/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM oven/bun:debian AS build -WORKDIR /app - -RUN apt-get update -y && \ - apt-get install -y --no-install-recommends curl ca-certificates gnupg && \ - curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ - apt-get install -y --no-install-recommends nodejs && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -ENV NODE_ENV=production - -COPY package.json bun.lock ./ -RUN bun install --frozen-lockfile - -COPY . . -RUN bun run build - -FROM nginx:alpine AS production - -RUN rm /etc/nginx/conf.d/default.conf -COPY .docker/casino.conf /etc/nginx/templates/nginx.conf.template -COPY .docker/entrypoint.sh /docker-entrypoint.d/40-custom-config-env.sh - -COPY --from=build /app/dist/casino /usr/share/nginx/html - -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/.docker/casino.conf b/frontend/.docker/casino.conf deleted file mode 100644 index 40b9613..0000000 --- a/frontend/.docker/casino.conf +++ /dev/null @@ -1,19 +0,0 @@ -server { - listen 80; - root /usr/share/nginx/html/browser; - index index.html; - - location / { - try_files $uri $uri/ /index.html; - add_header Cache-Control "no-cache"; - } - - location /backend/ { - proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT}/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - } -} diff --git a/frontend/.docker/entrypoint.sh b/frontend/.docker/entrypoint.sh deleted file mode 100755 index 7aa167e..0000000 --- a/frontend/.docker/entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# Default values if not provided -: ${BACKEND_HOST:=localhost} -: ${BACKEND_PORT:=8080} - -# Wait until the backend host is resolvable -echo "Waiting for backend host $BACKEND_HOST..." -until getent hosts "$BACKEND_HOST" > /dev/null; do - sleep 1 -done - -envsubst '$BACKEND_HOST $BACKEND_PORT' < /etc/nginx/templates/nginx.conf.template > /etc/nginx/conf.d/default.conf -exec nginx -g 'daemon off;' diff --git a/frontend/.dockerignore b/frontend/.dockerignore deleted file mode 100644 index 4e10341..0000000 --- a/frontend/.dockerignore +++ /dev/null @@ -1,15 +0,0 @@ -node_modules -dist -.angular -.git -.github -.vscode -.idea -*.md -!README.md -.DS_Store -.env* -npm-debug.log* -yarn-debug.log* -yarn-error.log* -bun-debug.log* \ No newline at end of file diff --git a/frontend/.editorconfig b/frontend/.editorconfig deleted file mode 100644 index 59d9a3a..0000000 --- a/frontend/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index cc7b141..0000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules -npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/frontend/.postcssrc.json b/frontend/.postcssrc.json deleted file mode 100644 index e092dc7..0000000 --- a/frontend/.postcssrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "plugins": { - "@tailwindcss/postcss": {} - } -} diff --git a/frontend/.prettierignore b/frontend/.prettierignore deleted file mode 100644 index f0c3bb3..0000000 --- a/frontend/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -coverage -node_modules -.angular diff --git a/frontend/.prettierrc b/frontend/.prettierrc deleted file mode 100644 index 837b4f9..0000000 --- a/frontend/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "es5", - "tabWidth": 2, - "semi": true, - "printWidth": 100, - "bracketSpacing": true, - "endOfLine": "lf" -} diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index daf35fe..0000000 --- a/frontend/README.md +++ /dev/null @@ -1,136 +0,0 @@ -# Casino Gaming Platform - Frontend - -This is the frontend application for the Casino Gaming Platform. It's built with Angular 18 and TailwindCSS, providing a responsive and modern UI for the casino gaming experience. - -## Development - -### Commands - -- **Build**: `bun run build` or `bunx @angular/cli build` -- **Start Dev Server**: `bun run start` or `bunx @angular/cli serve --proxy-config src/proxy.conf.json` -- **Format Code**: `bun run format` or `prettier --write "src/**/*.{ts,html,css,scss}"` -- **Lint**: `bun run lint` or `ng lint` -- **Test**: `bun run test` or `bunx @angular/cli test` -- **Test Single File**: `bunx @angular/cli test --include=path/to/test.spec.ts` - -## Style Guide - -### Color Palette - -#### Primary Colors -- Deep Blue: `#0a1219` (background) -- Deep Blue Light: `#121e27` (secondary background) -- Deep Blue Contrast: `#1a2835` (cards, elements) - -#### Accent Colors -- Emerald: `#10b981` (primary buttons) -- Emerald Dark: `#059669` (button hover) -- Emerald Light: `#34d399` (highlights) - -#### Text Colors -- Primary Text: `#ffffff` (white) -- Secondary Text: `#94a3b8` (light gray) -- Tertiary Text: `#64748b` (darker gray) - -#### Additional Accents -- Yellow: `#fbbf24` -- Red: `#ef4444` -- Purple: `#8b5cf6` - -### Typography - -#### Font Sizes -- Extra Small: Text-xs (footer disclaimers) -- Small: Text-sm (navigation links, footer links) -- Base: Text-base (general text) -- Large: Text-lg (section headings) -- Extra Large: Text-xl (stat numbers, game headings) -- Display: Text-4xl/5xl/7xl (welcome bonus text) - -#### Font Weights -- Normal: General text -- Medium: Labels -- Semibold: Navigation brand -- Bold: Headings, stats -- Extrabold: Welcome bonus text - -### Components - -#### Buttons -- Primary: Emerald background with hover state -- Secondary: Deep blue light background with hover state -- All buttons have active scale effect (95%) -- Transition duration: 200-300ms - -#### Cards -- Background: Deep blue contrast -- Rounded corners (lg) -- Shadow effects with hover transition -- Consistent padding (p-4) - -#### Navigation -- Desktop: Horizontal links with hover effects -- Mobile: Collapsible menu with toggle -- Links have color and background transitions - -#### Modals -- Backdrop blur with dark overlay -- Card-style container with emerald focus rings -- Consistent form styling with transitions - -### Forms - -#### Inputs -- Dark background with border -- Focus states with emerald accent -- Consistent padding and rounded corners -- Clear label positioning - -### Layout - -#### Grid System -- Mobile-first responsive grid -- Breakpoints: sm, md, lg -- Grid columns: 1 (mobile), 2 (tablet), 3 (desktop) -- Consistent gap spacing (gap-4) - -#### Spacing -- Consistent margin/padding scale -- Mobile-responsive spacing adjustments - -### Animation -- Transitions: 200-500ms duration -- Hover/active state animations -- Scale transformations (95-110%) -- Opacity transitions for navigation elements - -### Components & Classes - -#### Common UI Elements -- `.card` - Base card container -- `.button-primary` - Main CTA buttons -- `.button-secondary` - Alternative action buttons -- `.section-heading` - Section titles -- `.nav-link` - Navigation links -- `.modal-card` - Modal container - -#### Game Elements -- `.game-card-content` - Game information container -- `.game-heading-sm` - Small game titles -- `.game-heading-xl` - Large game titles -- `.game-text` - Game descriptions -- `.slider-container` - Game carousel container - -### Responsive Design -- Mobile-first approach -- Tailwind breakpoints (sm, md, lg) -- Different layouts based on screen size -- Responsive text sizing and spacing -- Hidden/visible elements using responsive classes - -### CSS Framework -- Tailwind CSS for utility classes -- Custom utility classes with @apply directive -- CSS variables for theming -- Component-based styling approach - diff --git a/frontend/angular.json b/frontend/angular.json deleted file mode 100644 index a9f9a84..0000000 --- a/frontend/angular.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "lf10Starter2024": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/casino", - "index": "src/index.html", - "browser": "src/main.ts", - "tsConfig": "tsconfig.app.json", - "assets": [ - { - "glob": "**/*", - "input": "public" - } - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kB", - "maximumError": "1MB" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kB", - "maximumError": "4kB" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "lf10Starter2024:build:production" - }, - "development": { - "buildTarget": "lf10Starter2024:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n" - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "tsConfig": "tsconfig.spec.json", - "assets": [ - { - "glob": "**/*", - "input": "public" - } - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-eslint/builder:lint", - "options": { - "lintFilePatterns": [ - "src/**/*.ts", - "src/**/*.html" - ] - } - } - } - } - }, - "cli": { - "analytics": "33c8483f-3876-4eb5-9c9b-1001cab9b273", - "packageManager": "bun", - "schematicCollections": [ - "angular-eslint" - ] - } -} diff --git a/frontend/bun.lock b/frontend/bun.lock deleted file mode 100644 index 5275e49..0000000 --- a/frontend/bun.lock +++ /dev/null @@ -1,2379 +0,0 @@ -{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "lf10-starter2024", - "dependencies": { - "@angular/animations": "^19.0.0", - "@angular/cdk": "~19.2.0", - "@angular/common": "^19.0.0", - "@angular/compiler": "^19.2.4", - "@angular/core": "^19.0.0", - "@angular/forms": "^19.0.0", - "@angular/platform-browser": "^19.0.0", - "@angular/platform-browser-dynamic": "^19.0.0", - "@angular/router": "^19.0.0", - "@fortawesome/angular-fontawesome": "^1.0.0", - "@fortawesome/fontawesome-svg-core": "^6.7.2", - "@fortawesome/free-brands-svg-icons": "^6.7.2", - "@fortawesome/free-solid-svg-icons": "^6.7.2", - "@stripe/stripe-js": "^7.0.0", - "@tailwindcss/postcss": "^4.0.3", - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "countup.js": "^2.8.0", - "gsap": "^3.12.7", - "postcss": "^8.5.1", - "rxjs": "~7.8.2", - "tailwindcss": "^4.0.3", - "tslib": "^2.3.0", - }, - "devDependencies": { - "@angular-devkit/build-angular": "^19.0.0", - "@angular/cli": "^19.2.5", - "@angular/compiler-cli": "^19.0.0", - "@types/jasmine": "~5.1.0", - "angular-eslint": "19.7.0", - "eslint": "^9.25.1", - "jasmine-core": "~5.7.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", - "prettier": "^3.4.2", - "typescript": "~5.8.0", - "typescript-eslint": "8.33.1", - }, - }, - }, - "packages": { - "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - - "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - - "@angular-devkit/architect": ["@angular-devkit/architect@0.1902.6", "", { "dependencies": { "@angular-devkit/core": "19.2.6", "rxjs": "7.8.1" } }, "sha512-Dx6yPxpaE5AhP6UtrVRDCc9Ihq9B65LAbmIh3dNOyeehratuaQS0TYNKjbpaevevJojW840DTg80N+CrlfYp9g=="], - - "@angular-devkit/build-angular": ["@angular-devkit/build-angular@19.2.6", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.1902.6", "@angular-devkit/build-webpack": "0.1902.6", "@angular-devkit/core": "19.2.6", "@angular/build": "19.2.6", "@babel/core": "7.26.10", "@babel/generator": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-transform-async-generator-functions": "7.26.8", "@babel/plugin-transform-async-to-generator": "7.25.9", "@babel/plugin-transform-runtime": "7.26.10", "@babel/preset-env": "7.26.9", "@babel/runtime": "7.26.10", "@discoveryjs/json-ext": "0.6.3", "@ngtools/webpack": "19.2.6", "@vitejs/plugin-basic-ssl": "1.2.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", "babel-loader": "9.2.1", "browserslist": "^4.21.5", "copy-webpack-plugin": "12.0.2", "css-loader": "7.1.2", "esbuild-wasm": "0.25.1", "fast-glob": "3.3.3", "http-proxy-middleware": "3.0.3", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", "less": "4.2.2", "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.3.1", "mini-css-extract-plugin": "2.9.2", "open": "10.1.0", "ora": "5.4.1", "picomatch": "4.0.2", "piscina": "4.8.0", "postcss": "8.5.2", "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", "sass": "1.85.0", "sass-loader": "16.0.5", "semver": "7.7.1", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", "terser": "5.39.0", "tree-kill": "1.2.2", "tslib": "2.8.1", "webpack": "5.98.0", "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.2.0", "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, "optionalDependencies": { "esbuild": "0.25.1" }, "peerDependencies": { "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", "@angular/ssr": "^19.2.6", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "karma": "^6.3.0", "ng-packagr": "^19.0.0 || ^19.2.0-next.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "typescript": ">=5.5 <5.9" }, "optionalPeers": ["@angular/localize", "@angular/platform-server", "@angular/service-worker", "@angular/ssr", "@web/test-runner", "browser-sync", "jest", "jest-environment-jsdom", "karma", "ng-packagr", "protractor", "tailwindcss"] }, "sha512-alYn3PSsiQML9PzU1VKbmYnIP2ULK/AqfjdeJFh8r6m8ZjUvX1zDy9TdAfC6fykQ2mGHyChteRckbx9uVOyhwQ=="], - - "@angular-devkit/build-webpack": ["@angular-devkit/build-webpack@0.1902.6", "", { "dependencies": { "@angular-devkit/architect": "0.1902.6", "rxjs": "7.8.1" }, "peerDependencies": { "webpack": "^5.30.0", "webpack-dev-server": "^5.0.2" } }, "sha512-SZe2Nk39lJIJmtXWU+zhKaFy0xoU8N7387bvjhO0AoNQeRBaaJ5SrRLXX2jUzGUuVgGVF+plaVooKrmEOeM6ug=="], - - "@angular-devkit/core": ["@angular-devkit/core@19.2.6", "", { "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", "picomatch": "4.0.2", "rxjs": "7.8.1", "source-map": "0.7.4" }, "peerDependencies": { "chokidar": "^4.0.0" }, "optionalPeers": ["chokidar"] }, "sha512-WFgiYhrDMq83UNaGRAneIM7CYYdBozD+yYA9BjoU8AgBLKtrvn6S8ZcjKAk5heoHtY/u8pEb0mwDTz9gxFmJZQ=="], - - "@angular-devkit/schematics": ["@angular-devkit/schematics@19.2.6", "", { "dependencies": { "@angular-devkit/core": "19.2.6", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "5.4.1", "rxjs": "7.8.1" } }, "sha512-YTAxNnT++5eflx19OUHmOWu597/TbTel+QARiZCv1xQw99+X8DCKKOUXtqBRd53CAHlREDI33Rn/JLY3NYgMLQ=="], - - "@angular-eslint/builder": ["@angular-eslint/builder@19.7.0", "", { "dependencies": { "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", "@angular-devkit/core": ">= 19.0.0 < 20.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-tnanOOwUKzeS0FwhjJd/dNeb8gVzcF0+cI4/ZgohOjZxm8fZqtzXcKfGS1C7KsR/CPHBdY9cbF1OVPJEarrnsQ=="], - - "@angular-eslint/bundled-angular-compiler": ["@angular-eslint/bundled-angular-compiler@19.7.0", "", {}, "sha512-95Z30MhQ93s1G1mEnsVuG45te82I+6dp8Y0MamRgyh4OZvOajmEXpvCwT+hkr/9WAroLZ7p5nlMbzAA+OXZ+YQ=="], - - "@angular-eslint/eslint-plugin": ["@angular-eslint/eslint-plugin@19.7.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.7.0", "@angular-eslint/utils": "19.7.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-M8OqDgiFSSxMinW/Gkdrvy2O2Oeo8bGk1DQc0s3aEKB44PYAjXC49jMSihvdozqtu1qjPBcTN5kvUwzwN5oWxA=="], - - "@angular-eslint/eslint-plugin-template": ["@angular-eslint/eslint-plugin-template@19.7.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.7.0", "@angular-eslint/utils": "19.7.0", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { "@angular-eslint/template-parser": "19.7.0", "@typescript-eslint/types": "^7.11.0 || ^8.0.0", "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-gR+RH7ZDFctupUsCcxWWloD0I7m9pE8HiDX9TrwrSQbNgzvp/P7+Mgv709rR1Jju9GSVavPh7EG3VgiCyR2m5w=="], - - "@angular-eslint/schematics": ["@angular-eslint/schematics@19.7.0", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/eslint-plugin": "19.7.0", "@angular-eslint/eslint-plugin-template": "19.7.0", "ignore": "7.0.5", "semver": "7.7.2", "strip-json-comments": "3.1.1" } }, "sha512-07j/qXfSLvLsUq8a7WJlGYgcgfVEJ1ODuwJ2R4686dh2lqZ5GRV75fpdOtOBdC38MILLwd5el+8LfdaIG19Yog=="], - - "@angular-eslint/template-parser": ["@angular-eslint/template-parser@19.7.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.7.0", "eslint-scope": "^8.0.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-XLPt6gk8VMOrUO9NWRpXN8zgwJuCDV+9y3KbVnd4WyakO0sOz9SVzktuI4AeY9jWS9/tqU6P8Uj0WZsMVz7F8w=="], - - "@angular-eslint/utils": ["@angular-eslint/utils@19.7.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.7.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-F4JcZtc2/Wl0AwRaeUywupPHdaOtldpwfrGYewT1dYDikFafyDk5T6E9JYv/HgLXROPNMDVPFquwikNvAPlfAg=="], - - "@angular/animations": ["@angular/animations@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/common": "19.2.5", "@angular/core": "19.2.5" } }, "sha512-m4RtY3z1JuHFCh6OrOHxo25oKEigBDdR/XmdCfXIwfTiObZzNA7VQhysgdrb9IISO99kXbjZUYKDtLzgWT8Klg=="], - - "@angular/build": ["@angular/build@19.2.6", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.1902.6", "@babel/core": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-syntax-import-attributes": "7.26.0", "@inquirer/confirm": "5.1.6", "@vitejs/plugin-basic-ssl": "1.2.0", "beasties": "0.2.0", "browserslist": "^4.23.0", "esbuild": "0.25.1", "fast-glob": "3.3.3", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "listr2": "8.2.5", "magic-string": "0.30.17", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.8.0", "rollup": "4.34.8", "sass": "1.85.0", "semver": "7.7.1", "source-map-support": "0.5.21", "vite": "6.2.4", "watchpack": "2.4.2" }, "optionalDependencies": { "lmdb": "3.2.6" }, "peerDependencies": { "@angular/compiler": "^19.0.0 || ^19.2.0-next.0", "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", "@angular/ssr": "^19.2.6", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^19.0.0 || ^19.2.0-next.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "typescript": ">=5.5 <5.9" }, "optionalPeers": ["@angular/localize", "@angular/platform-server", "@angular/service-worker", "@angular/ssr", "karma", "less", "ng-packagr", "postcss", "tailwindcss"] }, "sha512-+VBLb4ZPLswwJmgfsTFzGex+Sq/WveNc+uaIWyHYjwnuI17NXe1qAAg1rlp72CqGn0cirisfOyAUwPc/xZAgTg=="], - - "@angular/cdk": ["@angular/cdk@19.2.8", "", { "dependencies": { "parse5": "^7.1.2", "tslib": "^2.3.0" }, "peerDependencies": { "@angular/common": "^19.0.0 || ^20.0.0", "@angular/core": "^19.0.0 || ^20.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-ZZqWVYFF80TdjWkk2sc9Pn2luhiYeC78VH3Yjeln4wXMsTGDsvKPBcuOxSxxpJ31saaVBehDjBUuXMqGRj8KuA=="], - - "@angular/cli": ["@angular/cli@19.2.6", "", { "dependencies": { "@angular-devkit/architect": "0.1902.6", "@angular-devkit/core": "19.2.6", "@angular-devkit/schematics": "19.2.6", "@inquirer/prompts": "7.3.2", "@listr2/prompt-adapter-inquirer": "2.0.18", "@schematics/angular": "19.2.6", "@yarnpkg/lockfile": "1.1.0", "ini": "5.0.0", "jsonc-parser": "3.3.1", "listr2": "8.2.5", "npm-package-arg": "12.0.2", "npm-pick-manifest": "10.0.0", "pacote": "20.0.0", "resolve": "1.22.10", "semver": "7.7.1", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, "bin": { "ng": "bin/ng.js" } }, "sha512-eZhFOSsDUHKaciwcWdU5C54ViAvPPdZJf42So93G2vZWDtEq6Uk47huocn1FY9cMhDvURfYLNrrLMpUDtUSsSA=="], - - "@angular/common": ["@angular/common@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "19.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-vFCBdas4C5PxP6ts/4TlRddWD3DUmI3aaO0QZdZvqyLHy428t84ruYdsJXKaeD8ie2U4/9F3a1tsklclRG/BBA=="], - - "@angular/compiler": ["@angular/compiler@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-34J+HubQjwkbZ0AUtU5sa4Zouws9XtP/fKaysMQecoYJTZ3jewzLSRu3aAEZX1Y4gIrcVVKKIxM6oWoXKwYMOA=="], - - "@angular/compiler-cli": ["@angular/compiler-cli@19.2.5", "", { "dependencies": { "@babel/core": "7.26.9", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" }, "peerDependencies": { "@angular/compiler": "19.2.5", "typescript": ">=5.5 <5.9" }, "bin": { "ngc": "bundles/src/bin/ngc.js", "ngcc": "bundles/ngcc/index.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-b2cG41r6lilApXLlvja1Ra2D00dM3BxmQhoElKC1tOnpD6S3/krlH1DOnBB2I55RBn9iv4zdmPz1l8zPUSh7DQ=="], - - "@angular/core": ["@angular/core@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" } }, "sha512-NNEz1sEZz1mBpgf6Tz3aJ9b8KjqpTiMYhHfCYA9h9Ipe4D8gUmOsvPHPK2M755OX7p7PmUmzp1XCUHYrZMVHRw=="], - - "@angular/forms": ["@angular/forms@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/common": "19.2.5", "@angular/core": "19.2.5", "@angular/platform-browser": "19.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-2Zvy3qK1kOxiAX9fdSaeG48q7oyO/4RlMYlg1w+ra9qX1SrgwF3OQ2P2Vs+ojg1AxN3z9xFp4aYaaID/G2LZAw=="], - - "@angular/platform-browser": ["@angular/platform-browser@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "19.2.5", "@angular/common": "19.2.5", "@angular/core": "19.2.5" }, "optionalPeers": ["@angular/animations"] }, "sha512-Lshy++X16cvl6OPvfzMySpsqEaCPKEJmDjz7q7oSt96oxlh6LvOeOUVLjsNyrNaIt9NadpWoqjlu/I9RTPJkpw=="], - - "@angular/platform-browser-dynamic": ["@angular/platform-browser-dynamic@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/common": "19.2.5", "@angular/compiler": "19.2.5", "@angular/core": "19.2.5", "@angular/platform-browser": "19.2.5" } }, "sha512-15in8u4552EcdWNTXY2h0MKuJbk3AuXwWr0zVTum4CfB/Ss2tNTrDEdWhgAbhnUI0e9jZQee/fhBbA1rleMYrA=="], - - "@angular/router": ["@angular/router@19.2.5", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/common": "19.2.5", "@angular/core": "19.2.5", "@angular/platform-browser": "19.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-9pSfmdNXLjaOKj0kd4UxBC7sFdCFOnRGbftp397G3KWqsLsGSKmNFzqhXNeA5QHkaVxnpmpm8HzXU+zYV5JwSg=="], - - "@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], - - "@babel/compat-data": ["@babel/compat-data@7.26.8", "", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="], - - "@babel/core": ["@babel/core@7.26.10", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.10", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.10", "@babel/parser": "^7.26.10", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.10", "@babel/types": "^7.26.10", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ=="], - - "@babel/generator": ["@babel/generator@7.26.10", "", { "dependencies": { "@babel/parser": "^7.26.10", "@babel/types": "^7.26.10", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang=="], - - "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.0", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA=="], - - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-replace-supers": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/traverse": "^7.27.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg=="], - - "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ=="], - - "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw=="], - - "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw=="], - - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.26.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw=="], - - "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ=="], - - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="], - - "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-wrap-function": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw=="], - - "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.26.5", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/traverse": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg=="], - - "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA=="], - - "@babel/helper-split-export-declaration": ["@babel/helper-split-export-declaration@7.24.7", "", { "dependencies": { "@babel/types": "^7.24.7" } }, "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], - - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.25.9", "", {}, "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw=="], - - "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.25.9", "", { "dependencies": { "@babel/template": "^7.25.9", "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g=="], - - "@babel/helpers": ["@babel/helpers@7.27.0", "", { "dependencies": { "@babel/template": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg=="], - - "@babel/parser": ["@babel/parser@7.27.0", "", { "dependencies": { "@babel/types": "^7.27.0" }, "bin": "./bin/babel-parser.js" }, "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg=="], - - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g=="], - - "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw=="], - - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug=="], - - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g=="], - - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg=="], - - "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="], - - "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.26.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg=="], - - "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.26.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A=="], - - "@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="], - - "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg=="], - - "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-remap-async-to-generator": "^7.25.9", "@babel/traverse": "^7.26.8" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg=="], - - "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-remap-async-to-generator": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ=="], - - "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.26.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ=="], - - "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ=="], - - "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q=="], - - "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.26.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ=="], - - "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9", "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg=="], - - "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/template": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA=="], - - "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ=="], - - "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA=="], - - "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw=="], - - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog=="], - - "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg=="], - - "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.26.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ=="], - - "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww=="], - - "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.26.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg=="], - - "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA=="], - - "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw=="], - - "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ=="], - - "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q=="], - - "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA=="], - - "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw=="], - - "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.26.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.26.0", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ=="], - - "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA=="], - - "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw=="], - - "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA=="], - - "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ=="], - - "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.26.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw=="], - - "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q=="], - - "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg=="], - - "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A=="], - - "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g=="], - - "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A=="], - - "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g=="], - - "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw=="], - - "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw=="], - - "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA=="], - - "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "regenerator-transform": "^0.15.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA=="], - - "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.26.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw=="], - - "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg=="], - - "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.26.10", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.26.5", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NWaL2qG6HRpONTnj4JvDU6th4jYeZOJgu3QhmFTCihib0ermtOJqktA5BduGm3suhhVe9EMP9c9+mfJ/I9slqw=="], - - "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng=="], - - "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A=="], - - "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA=="], - - "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q=="], - - "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w=="], - - "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q=="], - - "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg=="], - - "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA=="], - - "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ=="], - - "@babel/preset-env": ["@babel/preset-env@7.26.9", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.26.0", "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.26.8", "@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-classes": "^7.25.9", "@babel/plugin-transform-computed-properties": "^7.25.9", "@babel/plugin-transform-destructuring": "^7.25.9", "@babel/plugin-transform-dotall-regex": "^7.25.9", "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-for-of": "^7.26.9", "@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", "@babel/plugin-transform-optional-catch-binding": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9", "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/plugin-transform-private-property-in-object": "^7.25.9", "@babel/plugin-transform-property-literals": "^7.25.9", "@babel/plugin-transform-regenerator": "^7.25.9", "@babel/plugin-transform-regexp-modifiers": "^7.26.0", "@babel/plugin-transform-reserved-words": "^7.25.9", "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.26.8", "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ=="], - - "@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="], - - "@babel/runtime": ["@babel/runtime@7.26.10", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw=="], - - "@babel/template": ["@babel/template@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA=="], - - "@babel/traverse": ["@babel/traverse@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", "@babel/parser": "^7.27.0", "@babel/template": "^7.27.0", "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA=="], - - "@babel/types": ["@babel/types@7.27.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg=="], - - "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], - - "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.6.3", "", {}, "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.1", "", { "os": "android", "cpu": "arm" }, "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.1", "", { "os": "android", "cpu": "arm64" }, "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.1", "", { "os": "android", "cpu": "x64" }, "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.1", "", { "os": "linux", "cpu": "arm" }, "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA=="], - - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.1", "", { "os": "none", "cpu": "arm64" }, "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.1", "", { "os": "none", "cpu": "x64" }, "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA=="], - - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.5.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], - - "@eslint/config-array": ["@eslint/config-array@0.20.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.2.1", "", {}, "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw=="], - - "@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], - - "@eslint/js": ["@eslint/js@9.25.1", "", {}, "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg=="], - - "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.8", "", { "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" } }, "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA=="], - - "@fortawesome/angular-fontawesome": ["@fortawesome/angular-fontawesome@1.0.0", "", { "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.7.1", "tslib": "^2.8.1" }, "peerDependencies": { "@angular/core": "^19.0.0" } }, "sha512-EC2fYuXIuw2ld1kzJi+zysWus6OeGGfLQtbh0hW9zyyq5aBo8ZJkcJKBsVQ8E6Mg7nHyTWaXn+sdcXTPDWz+UQ=="], - - "@fortawesome/fontawesome-common-types": ["@fortawesome/fontawesome-common-types@6.7.2", "", {}, "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg=="], - - "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA=="], - - "@fortawesome/free-brands-svg-icons": ["@fortawesome/free-brands-svg-icons@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q=="], - - "@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA=="], - - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], - - "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="], - - "@inquirer/checkbox": ["@inquirer/checkbox@4.1.4", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/figures": "^1.0.11", "@inquirer/type": "^3.0.5", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-d30576EZdApjAMceijXA5jDzRQHT/MygbC+J8I7EqA6f/FRpYxlRtRJbHF8gHeWYeSdOuTEJqonn7QLB1ELezA=="], - - "@inquirer/confirm": ["@inquirer/confirm@5.1.6", "", { "dependencies": { "@inquirer/core": "^10.1.7", "@inquirer/type": "^3.0.4" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-6ZXYK3M1XmaVBZX6FCfChgtponnL0R6I7k8Nu+kaoNkT828FVZTcca1MqmWQipaW2oNREQl5AaPCUOOCVNdRMw=="], - - "@inquirer/core": ["@inquirer/core@10.1.9", "", { "dependencies": { "@inquirer/figures": "^1.0.11", "@inquirer/type": "^3.0.5", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-sXhVB8n20NYkUBfDYgizGHlpRVaCRjtuzNZA6xpALIUbkgfd2Hjz+DfEN6+h1BRnuxw0/P4jCIMjMsEOAMwAJw=="], - - "@inquirer/editor": ["@inquirer/editor@4.2.9", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5", "external-editor": "^3.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-8HjOppAxO7O4wV1ETUlJFg6NDjp/W2NP5FB9ZPAcinAlNT4ZIWOLe2pUVwmmPRSV0NMdI5r/+lflN55AwZOKSw=="], - - "@inquirer/expand": ["@inquirer/expand@4.0.11", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-OZSUW4hFMW2TYvX/Sv+NnOZgO8CHT2TU1roUCUIF2T+wfw60XFRRp9MRUPCT06cRnKL+aemt2YmTWwt7rOrNEA=="], - - "@inquirer/figures": ["@inquirer/figures@1.0.11", "", {}, "sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw=="], - - "@inquirer/input": ["@inquirer/input@4.1.8", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-WXJI16oOZ3/LiENCAxe8joniNp8MQxF6Wi5V+EBbVA0ZIOpFcL4I9e7f7cXse0HJeIPCWO8Lcgnk98juItCi7Q=="], - - "@inquirer/number": ["@inquirer/number@3.0.11", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-pQK68CsKOgwvU2eA53AG/4npRTH2pvs/pZ2bFvzpBhrznh8Mcwt19c+nMO7LHRr3Vreu1KPhNBF3vQAKrjIulw=="], - - "@inquirer/password": ["@inquirer/password@4.0.11", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5", "ansi-escapes": "^4.3.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-dH6zLdv+HEv1nBs96Case6eppkRggMe8LoOTl30+Gq5Wf27AO/vHFgStTVz4aoevLdNXqwE23++IXGw4eiOXTg=="], - - "@inquirer/prompts": ["@inquirer/prompts@7.3.2", "", { "dependencies": { "@inquirer/checkbox": "^4.1.2", "@inquirer/confirm": "^5.1.6", "@inquirer/editor": "^4.2.7", "@inquirer/expand": "^4.0.9", "@inquirer/input": "^4.1.6", "@inquirer/number": "^3.0.9", "@inquirer/password": "^4.0.9", "@inquirer/rawlist": "^4.0.9", "@inquirer/search": "^3.0.9", "@inquirer/select": "^4.0.9" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ=="], - - "@inquirer/rawlist": ["@inquirer/rawlist@4.0.11", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/type": "^3.0.5", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-uAYtTx0IF/PqUAvsRrF3xvnxJV516wmR6YVONOmCWJbbt87HcDHLfL9wmBQFbNJRv5kCjdYKrZcavDkH3sVJPg=="], - - "@inquirer/search": ["@inquirer/search@3.0.11", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/figures": "^1.0.11", "@inquirer/type": "^3.0.5", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-9CWQT0ikYcg6Ls3TOa7jljsD7PgjcsYEM0bYE+Gkz+uoW9u8eaJCRHJKkucpRE5+xKtaaDbrND+nPDoxzjYyew=="], - - "@inquirer/select": ["@inquirer/select@4.1.0", "", { "dependencies": { "@inquirer/core": "^10.1.9", "@inquirer/figures": "^1.0.11", "@inquirer/type": "^3.0.5", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-z0a2fmgTSRN+YBuiK1ROfJ2Nvrpij5lVN3gPDkQGhavdvIVGHGW29LwYZfM/j42Ai2hUghTI/uoBuTbrJk42bA=="], - - "@inquirer/type": ["@inquirer/type@1.5.5", "", { "dependencies": { "mute-stream": "^1.0.0" } }, "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA=="], - - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - - "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - - "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], - - "@jridgewell/source-map": ["@jridgewell/source-map@0.3.6", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], - - "@jsonjoy.com/base64": ["@jsonjoy.com/base64@1.1.2", "", { "peerDependencies": { "tslib": "2" } }, "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA=="], - - "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.2.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", "hyperdyperid": "^1.2.0", "thingies": "^1.20.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA=="], - - "@jsonjoy.com/util": ["@jsonjoy.com/util@1.5.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA=="], - - "@leichtgewicht/ip-codec": ["@leichtgewicht/ip-codec@2.0.5", "", {}, "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="], - - "@listr2/prompt-adapter-inquirer": ["@listr2/prompt-adapter-inquirer@2.0.18", "", { "dependencies": { "@inquirer/type": "^1.5.5" }, "peerDependencies": { "@inquirer/prompts": ">= 3 < 8" } }, "sha512-0hz44rAcrphyXcA8IS7EJ2SCoaBZD2u5goE8S/e+q/DL+dOGpqpcLidVOFeLG3VgML62SXmfRLAhWt0zL1oW4Q=="], - - "@lmdb/lmdb-darwin-arm64": ["@lmdb/lmdb-darwin-arm64@3.2.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-yF/ih9EJJZc72psFQbwnn8mExIWfTnzWJg+N02hnpXtDPETYLmQswIMBn7+V88lfCaFrMozJsUvcEQIkEPU0Gg=="], - - "@lmdb/lmdb-darwin-x64": ["@lmdb/lmdb-darwin-x64@3.2.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-5BbCumsFLbCi586Bb1lTWQFkekdQUw8/t8cy++Uq251cl3hbDIGEwD9HAwh8H6IS2F6QA9KdKmO136LmipRNkg=="], - - "@lmdb/lmdb-linux-arm": ["@lmdb/lmdb-linux-arm@3.2.6", "", { "os": "linux", "cpu": "arm" }, "sha512-+6XgLpMb7HBoWxXj+bLbiiB4s0mRRcDPElnRS3LpWRzdYSe+gFk5MT/4RrVNqd2MESUDmb53NUXw1+BP69bjiQ=="], - - "@lmdb/lmdb-linux-arm64": ["@lmdb/lmdb-linux-arm64@3.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-l5VmJamJ3nyMmeD1ANBQCQqy7do1ESaJQfKPSm2IG9/ADZryptTyCj8N6QaYgIWewqNUrcbdMkJajRQAt5Qjfg=="], - - "@lmdb/lmdb-linux-x64": ["@lmdb/lmdb-linux-x64@3.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-nDYT8qN9si5+onHYYaI4DiauDMx24OAiuZAUsEqrDy+ja/3EbpXPX/VAkMV8AEaQhy3xc4dRC+KcYIvOFefJ4Q=="], - - "@lmdb/lmdb-win32-x64": ["@lmdb/lmdb-win32-x64@3.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-XlqVtILonQnG+9fH2N3Aytria7P/1fwDgDhl29rde96uH2sLB8CHORIf2PfuLVzFQJ7Uqp8py9AYwr3ZUCFfWg=="], - - "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], - - "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], - - "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw=="], - - "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg=="], - - "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg=="], - - "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], - - "@napi-rs/nice": ["@napi-rs/nice@1.0.1", "", { "optionalDependencies": { "@napi-rs/nice-android-arm-eabi": "1.0.1", "@napi-rs/nice-android-arm64": "1.0.1", "@napi-rs/nice-darwin-arm64": "1.0.1", "@napi-rs/nice-darwin-x64": "1.0.1", "@napi-rs/nice-freebsd-x64": "1.0.1", "@napi-rs/nice-linux-arm-gnueabihf": "1.0.1", "@napi-rs/nice-linux-arm64-gnu": "1.0.1", "@napi-rs/nice-linux-arm64-musl": "1.0.1", "@napi-rs/nice-linux-ppc64-gnu": "1.0.1", "@napi-rs/nice-linux-riscv64-gnu": "1.0.1", "@napi-rs/nice-linux-s390x-gnu": "1.0.1", "@napi-rs/nice-linux-x64-gnu": "1.0.1", "@napi-rs/nice-linux-x64-musl": "1.0.1", "@napi-rs/nice-win32-arm64-msvc": "1.0.1", "@napi-rs/nice-win32-ia32-msvc": "1.0.1", "@napi-rs/nice-win32-x64-msvc": "1.0.1" } }, "sha512-zM0mVWSXE0a0h9aKACLwKmD6nHcRiKrPpCfvaKqG1CqDEyjEawId0ocXxVzPMCAm6kkWr2P025msfxXEnt8UGQ=="], - - "@napi-rs/nice-android-arm-eabi": ["@napi-rs/nice-android-arm-eabi@1.0.1", "", { "os": "android", "cpu": "arm" }, "sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w=="], - - "@napi-rs/nice-android-arm64": ["@napi-rs/nice-android-arm64@1.0.1", "", { "os": "android", "cpu": "arm64" }, "sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA=="], - - "@napi-rs/nice-darwin-arm64": ["@napi-rs/nice-darwin-arm64@1.0.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-91k3HEqUl2fsrz/sKkuEkscj6EAj3/eZNCLqzD2AA0TtVbkQi8nqxZCZDMkfklULmxLkMxuUdKe7RvG/T6s2AA=="], - - "@napi-rs/nice-darwin-x64": ["@napi-rs/nice-darwin-x64@1.0.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ=="], - - "@napi-rs/nice-freebsd-x64": ["@napi-rs/nice-freebsd-x64@1.0.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw=="], - - "@napi-rs/nice-linux-arm-gnueabihf": ["@napi-rs/nice-linux-arm-gnueabihf@1.0.1", "", { "os": "linux", "cpu": "arm" }, "sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q=="], - - "@napi-rs/nice-linux-arm64-gnu": ["@napi-rs/nice-linux-arm64-gnu@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA=="], - - "@napi-rs/nice-linux-arm64-musl": ["@napi-rs/nice-linux-arm64-musl@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw=="], - - "@napi-rs/nice-linux-ppc64-gnu": ["@napi-rs/nice-linux-ppc64-gnu@1.0.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q=="], - - "@napi-rs/nice-linux-riscv64-gnu": ["@napi-rs/nice-linux-riscv64-gnu@1.0.1", "", { "os": "linux", "cpu": "none" }, "sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig=="], - - "@napi-rs/nice-linux-s390x-gnu": ["@napi-rs/nice-linux-s390x-gnu@1.0.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg=="], - - "@napi-rs/nice-linux-x64-gnu": ["@napi-rs/nice-linux-x64-gnu@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA=="], - - "@napi-rs/nice-linux-x64-musl": ["@napi-rs/nice-linux-x64-musl@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ=="], - - "@napi-rs/nice-win32-arm64-msvc": ["@napi-rs/nice-win32-arm64-msvc@1.0.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg=="], - - "@napi-rs/nice-win32-ia32-msvc": ["@napi-rs/nice-win32-ia32-msvc@1.0.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw=="], - - "@napi-rs/nice-win32-x64-msvc": ["@napi-rs/nice-win32-x64-msvc@1.0.1", "", { "os": "win32", "cpu": "x64" }, "sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg=="], - - "@ngtools/webpack": ["@ngtools/webpack@19.2.6", "", { "peerDependencies": { "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", "typescript": ">=5.5 <5.9", "webpack": "^5.54.0" } }, "sha512-/jWpZUoMru3YbRJAPZ2KroUSzE6Ak5Hav219raYQaBXVtyLAvFE5VC1/CiH0wTYnb/dyjxzWq38ftOr/vv0+tg=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@npmcli/agent": ["@npmcli/agent@3.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q=="], - - "@npmcli/fs": ["@npmcli/fs@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q=="], - - "@npmcli/git": ["@npmcli/git@6.0.3", "", { "dependencies": { "@npmcli/promise-spawn": "^8.0.0", "ini": "^5.0.0", "lru-cache": "^10.0.1", "npm-pick-manifest": "^10.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^5.0.0" } }, "sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ=="], - - "@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@3.0.0", "", { "dependencies": { "npm-bundled": "^4.0.0", "npm-normalize-package-bin": "^4.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q=="], - - "@npmcli/node-gyp": ["@npmcli/node-gyp@4.0.0", "", {}, "sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA=="], - - "@npmcli/package-json": ["@npmcli/package-json@6.1.1", "", { "dependencies": { "@npmcli/git": "^6.0.0", "glob": "^10.2.2", "hosted-git-info": "^8.0.0", "json-parse-even-better-errors": "^4.0.0", "proc-log": "^5.0.0", "semver": "^7.5.3", "validate-npm-package-license": "^3.0.4" } }, "sha512-d5qimadRAUCO4A/Txw71VM7UrRZzV+NPclxz/dc+M6B2oYwjWTjqh8HA/sGQgs9VZuJ6I/P7XIAlJvgrl27ZOw=="], - - "@npmcli/promise-spawn": ["@npmcli/promise-spawn@8.0.2", "", { "dependencies": { "which": "^5.0.0" } }, "sha512-/bNJhjc+o6qL+Dwz/bqfTQClkEO5nTQ1ZEcdCkAQjhkZMHIh22LPG7fNh1enJP1NKWDqYiiABnjFCY7E0zHYtQ=="], - - "@npmcli/redact": ["@npmcli/redact@3.1.1", "", {}, "sha512-3Hc2KGIkrvJWJqTbvueXzBeZlmvoOxc2jyX00yzr3+sNFquJg0N8hH4SAPLPVrkWIRQICVpVgjrss971awXVnA=="], - - "@npmcli/run-script": ["@npmcli/run-script@9.1.0", "", { "dependencies": { "@npmcli/node-gyp": "^4.0.0", "@npmcli/package-json": "^6.0.0", "@npmcli/promise-spawn": "^8.0.0", "node-gyp": "^11.0.0", "proc-log": "^5.0.0", "which": "^5.0.0" } }, "sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg=="], - - "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], - - "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], - - "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], - - "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], - - "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], - - "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], - - "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], - - "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], - - "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], - - "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], - - "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], - - "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], - - "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], - - "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="], - - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="], - - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="], - - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="], - - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="], - - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="], - - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="], - - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="], - - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="], - - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="], - - "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="], - - "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="], - - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="], - - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="], - - "@schematics/angular": ["@schematics/angular@19.2.6", "", { "dependencies": { "@angular-devkit/core": "19.2.6", "@angular-devkit/schematics": "19.2.6", "jsonc-parser": "3.3.1" } }, "sha512-fmbF9ONmEZqxHocCwOSWG2mHp4a22d1uW+DZUBUgZSBUFIrnFw42deOxDq8mkZOZ1Tc73UpLN2GKI7iJeUqS2A=="], - - "@sigstore/bundle": ["@sigstore/bundle@3.1.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.4.0" } }, "sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag=="], - - "@sigstore/core": ["@sigstore/core@2.0.0", "", {}, "sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg=="], - - "@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.4.0", "", {}, "sha512-o09cLSIq9EKyRXwryWDOJagkml9XgQCoCSRjHOnHLnvsivaW7Qznzz6yjfV7PHJHhIvyp8OH7OX8w0Dc5bQK7A=="], - - "@sigstore/sign": ["@sigstore/sign@3.1.0", "", { "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", "@sigstore/protobuf-specs": "^0.4.0", "make-fetch-happen": "^14.0.2", "proc-log": "^5.0.0", "promise-retry": "^2.0.1" } }, "sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw=="], - - "@sigstore/tuf": ["@sigstore/tuf@3.1.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.4.0", "tuf-js": "^3.0.1" } }, "sha512-suVMQEA+sKdOz5hwP9qNcEjX6B45R+hFFr4LAWzbRc5O+U2IInwvay/bpG5a4s+qR35P/JK/PiKiRGjfuLy1IA=="], - - "@sigstore/verify": ["@sigstore/verify@2.1.0", "", { "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", "@sigstore/protobuf-specs": "^0.4.0" } }, "sha512-kAAM06ca4CzhvjIZdONAL9+MLppW3K48wOFy1TbuaWFW/OMfl8JuTgW0Bm02JB1WJGT/ET2eqav0KTEKmxqkIA=="], - - "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="], - - "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], - - "@stripe/stripe-js": ["@stripe/stripe-js@7.0.0", "", {}, "sha512-0AWkP+hoIXB5O34FGY7jh687ZPlOqLqMkJDkiSXcp4TaWWidnxjsZSp0xkjyAWbIz4+j1BFXDAK01Rqb7ceBRA=="], - - "@tailwindcss/node": ["@tailwindcss/node@4.1.1", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.1" } }, "sha512-xvlh4pvfG/bkv0fEtJDABAm1tjtSmSyi2QmS4zyj1EKNI1UiOYiUq1IphSwDsNJ5vJ9cWEGs4rJXpUdCN2kujQ=="], - - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.1", "@tailwindcss/oxide-darwin-arm64": "4.1.1", "@tailwindcss/oxide-darwin-x64": "4.1.1", "@tailwindcss/oxide-freebsd-x64": "4.1.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.1", "@tailwindcss/oxide-linux-arm64-musl": "4.1.1", "@tailwindcss/oxide-linux-x64-gnu": "4.1.1", "@tailwindcss/oxide-linux-x64-musl": "4.1.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.1", "@tailwindcss/oxide-win32-x64-msvc": "4.1.1" } }, "sha512-7+YBgnPQ4+jv6B6WVOerJ6WOzDzNJXrRKDts674v6TKAqFqYRr9+EBtSziO7nNcwQ8JtoZNMeqA+WJDjtCM/7w=="], - - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.1", "", { "os": "android", "cpu": "arm64" }, "sha512-gTyRzfdParpoCU1yyUC/iN6XK6T0Ra4bDlF8Aeul5NP9cLzKEZDogdNVNGv5WZmCDkVol7qlex7TMmcfytMmmw=="], - - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-dI0QbdMWBvLB3MtaTKetzUKG9CUUQow8JSP4Nm+OxVokeZ+N+f1OmZW/hW1LzMxpx9RQCBgSRL+IIvKRat5Wdg=="], - - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-2Y+NPQOTRBCItshPgY/CWg4bKi7E9evMg4bgdb6h9iZObCZLOe3doPcuSxGS3DB0dKyMFKE8pTdWtFUbxZBMSA=="], - - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-N97NGMsB/7CHShbc5ube4dcsW/bYENkBrg8yWi8ieN9boYVRdw3cZviVryV/Nfu9bKbBV9kUvduFF2qBI7rEqg=="], - - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.1", "", { "os": "linux", "cpu": "arm" }, "sha512-33Lk6KbHnUZbXqza6RWNFo9wqPQ4+H5BAn1CkUUfC1RZ1vYbyDN6+iJPj53wmnWJ3mhRI8jWt3Jt1fO02IVdUQ=="], - - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LyW35RzSUy+80WYScv03HKasAUmMFDaSbNpWfk1gG5gEE9kuRGnDzSrqMoLAmY/kzMCYP/1kqmUiAx8EFLkI2A=="], - - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1KPnDMlHdqjPTUSFjx55pafvs8RZXRgxfeRgUrukwDKkuj7gFk28vW3Mx65YdiugAc9NWs3VgueZWaM1Po6uGw=="], - - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-4WdzA+MRlsinEEE6yxNMLJxpw0kE9XVipbAKdTL8BeUpyC2TdA3TL46lBulXzKp3BIxh3nqyR/UCqzl5o+3waQ=="], - - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-q7Ugbw3ARcjCW2VMUYrcMbJ6aMQuWPArBBE2EqC/swPZTdGADvMQSlvR0VKusUM4HoSsO7ZbvcZ53YwR57+AKw=="], - - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-0KpqsovgHcIzm7eAGzzEZsEs0/nPYXnRBv+aPq/GehpNQuE/NAQu+YgZXIIof+VflDFuyXOEnaFr7T5MZ1INhA=="], - - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-B1mjeXNS26kBOHv5sXARf6Wd0PWHV9x1TDlW0ummrBUOUAxAy5wcy4Nii1wzNvCdvC448hgiL06ylhwAbNthmg=="], - - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.1", "@tailwindcss/oxide": "4.1.1", "postcss": "^8.4.41", "tailwindcss": "4.1.1" } }, "sha512-GX9AEM+msH0i2Yh1b6CuDRaZRo3kmbvIrLbSfvJ53C3uaAgsQ//fTQAh9HMQ6t1a9zvoUptlYqG//plWsBQTCw=="], - - "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], - - "@tufjs/models": ["@tufjs/models@3.0.1", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.5" } }, "sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA=="], - - "@types/body-parser": ["@types/body-parser@1.19.5", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg=="], - - "@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="], - - "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], - - "@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="], - - "@types/cors": ["@types/cors@2.8.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA=="], - - "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], - - "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], - - "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], - - "@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="], - - "@types/express-serve-static-core": ["@types/express-serve-static-core@5.0.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA=="], - - "@types/http-errors": ["@types/http-errors@2.0.4", "", {}, "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="], - - "@types/http-proxy": ["@types/http-proxy@1.17.16", "", { "dependencies": { "@types/node": "*" } }, "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w=="], - - "@types/jasmine": ["@types/jasmine@5.1.7", "", {}, "sha512-DVOfk9FaClQfNFpSfaML15jjB5cjffDMvjtph525sroR5BEAW2uKnTOYUTqTFuZFjNvH0T5XMIydvIctnUKufw=="], - - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - - "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], - - "@types/node": ["@types/node@22.14.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA=="], - - "@types/node-forge": ["@types/node-forge@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ=="], - - "@types/qs": ["@types/qs@6.9.18", "", {}, "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA=="], - - "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], - - "@types/retry": ["@types/retry@0.12.2", "", {}, "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow=="], - - "@types/send": ["@types/send@0.17.4", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA=="], - - "@types/serve-index": ["@types/serve-index@1.9.4", "", { "dependencies": { "@types/express": "*" } }, "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug=="], - - "@types/serve-static": ["@types/serve-static@1.15.7", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "*" } }, "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw=="], - - "@types/sockjs": ["@types/sockjs@0.3.36", "", { "dependencies": { "@types/node": "*" } }, "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q=="], - - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.33.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/type-utils": "8.33.1", "@typescript-eslint/utils": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.33.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.33.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.0", "@typescript-eslint/types": "^8.33.0", "debug": "^4.3.4" } }, "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.0", "", { "dependencies": { "@typescript-eslint/types": "8.33.0", "@typescript-eslint/visitor-keys": "8.33.0" } }, "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.33.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/utils": "8.33.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.33.0", "", {}, "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.0", "@typescript-eslint/tsconfig-utils": "8.33.0", "@typescript-eslint/types": "8.33.0", "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.33.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.33.0", "@typescript-eslint/types": "8.33.0", "@typescript-eslint/typescript-estree": "8.33.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ=="], - - "@vitejs/plugin-basic-ssl": ["@vitejs/plugin-basic-ssl@1.2.0", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" } }, "sha512-mkQnxTkcldAzIsomk1UuLfAu9n+kpQ3JbHcpCp7d2Oo6ITtji8pHS3QToOWjhPFvNQSnhlkAjmGbhv2QvwO/7Q=="], - - "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], - - "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="], - - "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.13.2", "", {}, "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ=="], - - "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.14.1", "", {}, "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA=="], - - "@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.13.2", "", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA=="], - - "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.13.2", "", {}, "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA=="], - - "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/wasm-gen": "1.14.1" } }, "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw=="], - - "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.13.2", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw=="], - - "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.13.2", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw=="], - - "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.13.2", "", {}, "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ=="], - - "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/helper-wasm-section": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-opt": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1", "@webassemblyjs/wast-printer": "1.14.1" } }, "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ=="], - - "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg=="], - - "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1" } }, "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw=="], - - "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ=="], - - "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw=="], - - "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="], - - "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], - - "@yarnpkg/lockfile": ["@yarnpkg/lockfile@1.1.0", "", {}, "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="], - - "abbrev": ["abbrev@3.0.0", "", {}, "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA=="], - - "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], - - "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - - "adjust-sourcemap-loader": ["adjust-sourcemap-loader@4.0.0", "", { "dependencies": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" } }, "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A=="], - - "agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="], - - "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - - "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - - "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], - - "angular-eslint": ["angular-eslint@19.7.0", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/builder": "19.7.0", "@angular-eslint/eslint-plugin": "19.7.0", "@angular-eslint/eslint-plugin-template": "19.7.0", "@angular-eslint/schematics": "19.7.0", "@angular-eslint/template-parser": "19.7.0", "@typescript-eslint/types": "^8.0.0", "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*", "typescript-eslint": "^8.0.0" } }, "sha512-ujlc8CR40RYEWUctpVEg41ZCtmKnWeJH0mzORhzf0NVZb6FLhoNhmDPr1byw4Bcxzl0DAoNgKBhJymt6FNL6Rw=="], - - "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], - - "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], - - "ansi-html-community": ["ansi-html-community@0.0.8", "", { "bin": { "ansi-html": "bin/ansi-html" } }, "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="], - - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - - "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], - - "autoprefixer": ["autoprefixer@10.4.20", "", { "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g=="], - - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - - "babel-loader": ["babel-loader@9.2.1", "", { "dependencies": { "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" }, "peerDependencies": { "@babel/core": "^7.12.0", "webpack": ">=5" } }, "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA=="], - - "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.13", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.4", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g=="], - - "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.11.1", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3", "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ=="], - - "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.4", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.4" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw=="], - - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - - "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], - - "batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="], - - "beasties": ["beasties@0.2.0", "", { "dependencies": { "css-select": "^5.1.0", "css-what": "^6.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "htmlparser2": "^9.1.0", "picocolors": "^1.1.1", "postcss": "^8.4.49", "postcss-media-query-parser": "^0.2.3" } }, "sha512-Ljqskqx/tbZagIglYoJIMzH5zgssyp+in9+9sAyh15N22AornBeIDnb8EZ6Rk+6ShfMxd92uO3gfpT0NtZbpow=="], - - "big.js": ["big.js@5.2.2", "", {}, "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="], - - "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], - - "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], - - "bonjour-service": ["bonjour-service@1.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA=="], - - "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - - "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="], - - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - - "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - - "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], - - "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - - "cacache": ["cacache@19.0.1", "", { "dependencies": { "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^12.0.0", "tar": "^7.4.3", "unique-filename": "^4.0.0" } }, "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ=="], - - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - - "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001709", "", {}, "sha512-NgL3vUTnDrPCZ3zTahp4fsugQ4dc7EKTSzwQDPEel6DMoMnfH2jhry9n2Zm8onbSR+f/QtKHFOA+iAQu4kbtWA=="], - - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], - - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - - "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], - - "chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="], - - "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], - - "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], - - "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="], - - "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="], - - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - - "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], - - "clone-deep": ["clone-deep@4.0.1", "", { "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", "shallow-clone": "^3.0.0" } }, "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ=="], - - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], - - "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - - "common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="], - - "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], - - "compression": ["compression@1.8.0", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.0.2", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA=="], - - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - - "connect": ["connect@3.7.0", "", { "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", "parseurl": "~1.3.3", "utils-merge": "1.0.1" } }, "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ=="], - - "connect-history-api-fallback": ["connect-history-api-fallback@2.0.0", "", {}, "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA=="], - - "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], - - "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], - - "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], - - "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], - - "copy-anything": ["copy-anything@2.0.6", "", { "dependencies": { "is-what": "^3.14.1" } }, "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw=="], - - "copy-webpack-plugin": ["copy-webpack-plugin@12.0.2", "", { "dependencies": { "fast-glob": "^3.3.2", "glob-parent": "^6.0.1", "globby": "^14.0.0", "normalize-path": "^3.0.0", "schema-utils": "^4.2.0", "serialize-javascript": "^6.0.2" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA=="], - - "core-js-compat": ["core-js-compat@3.41.0", "", { "dependencies": { "browserslist": "^4.24.4" } }, "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A=="], - - "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], - - "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], - - "cosmiconfig": ["cosmiconfig@9.0.0", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg=="], - - "countup.js": ["countup.js@2.8.0", "", {}, "sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "css-loader": ["css-loader@7.1.2", "", { "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "webpack": "^5.27.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA=="], - - "css-select": ["css-select@5.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg=="], - - "css-what": ["css-what@6.1.0", "", {}, "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="], - - "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - - "custom-event": ["custom-event@1.0.1", "", {}, "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg=="], - - "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], - - "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], - - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], - - "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], - - "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], - - "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], - - "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], - - "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], - - "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - - "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], - - "di": ["di@0.0.1", "", {}, "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA=="], - - "dns-packet": ["dns-packet@5.6.1", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw=="], - - "dom-serialize": ["dom-serialize@2.2.1", "", { "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", "extend": "^3.0.0", "void-elements": "^2.0.0" } }, "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ=="], - - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], - - "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], - - "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - - "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], - - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - - "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.130", "", {}, "sha512-Ou2u7L9j2XLZbhqzyX0jWDj6gA8D3jIfVzt4rikLf3cGBa0VdReuFimBKS9tQJA4+XpeCxj1NoWlfBXzbMa9IA=="], - - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "emojis-list": ["emojis-list@3.0.0", "", {}, "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="], - - "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - - "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], - - "engine.io": ["engine.io@6.6.4", "", { "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1" } }, "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g=="], - - "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], - - "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], - - "ent": ["ent@2.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "punycode": "^1.4.1", "safe-regex-test": "^1.1.0" } }, "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw=="], - - "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - - "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], - - "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], - - "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], - - "errno": ["errno@0.1.8", "", { "dependencies": { "prr": "~1.0.1" }, "bin": { "errno": "cli.js" } }, "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A=="], - - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], - - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], - - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - - "es-module-lexer": ["es-module-lexer@1.6.0", "", {}, "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="], - - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], - - "esbuild": ["esbuild@0.25.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ=="], - - "esbuild-wasm": ["esbuild-wasm@0.25.1", "", { "bin": { "esbuild": "bin/esbuild" } }, "sha512-dZxPeDHcDIQ6ilml/NzYxnPbNkoVsHSFH3JGLSobttc5qYYgExMo8lh2XcB+w+AfiqykVDGK5PWanGB0gWaAWw=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], - - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@9.25.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.13.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.25.1", "@eslint/plugin-kit": "^0.2.8", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ=="], - - "eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], - - "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="], - - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - - "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], - - "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], - - "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], - - "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], - - "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], - - "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], - - "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - - "fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], - - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - - "faye-websocket": ["faye-websocket@0.11.4", "", { "dependencies": { "websocket-driver": ">=0.5.1" } }, "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="], - - "fdir": ["fdir@6.4.3", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw=="], - - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "finalhandler": ["finalhandler@1.1.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" } }, "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="], - - "find-cache-dir": ["find-cache-dir@4.0.0", "", { "dependencies": { "common-path-prefix": "^3.0.0", "pkg-dir": "^7.0.0" } }, "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg=="], - - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], - - "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - - "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - - "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], - - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - - "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], - - "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], - - "fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], - - "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], - - "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - - "get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], - - "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], - - "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - - "globby": ["globby@14.1.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.3", "ignore": "^7.0.3", "path-type": "^6.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.3.0" } }, "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA=="], - - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - - "gsap": ["gsap@3.12.7", "", {}, "sha512-V4GsyVamhmKefvcAKaoy0h6si0xX7ogwBoBSs2CTJwt7luW0oZzC0LhdkyuKV8PJAXr7Yaj8pMjCKD4GJ+eEMg=="], - - "handle-thing": ["handle-thing@2.0.1", "", {}, "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - - "hosted-git-info": ["hosted-git-info@8.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-sYKnA7eGln5ov8T8gnYlkSOxFJvywzEx9BueN6xo/GKO8PGiI6uK6xx+DIGe45T3bdVjLAQDQW1aicT8z8JwQg=="], - - "hpack.js": ["hpack.js@2.1.6", "", { "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", "readable-stream": "^2.0.1", "wbuf": "^1.1.0" } }, "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="], - - "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], - - "htmlparser2": ["htmlparser2@9.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "entities": "^4.5.0" } }, "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ=="], - - "http-cache-semantics": ["http-cache-semantics@4.1.1", "", {}, "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="], - - "http-deceiver": ["http-deceiver@1.2.7", "", {}, "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw=="], - - "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], - - "http-parser-js": ["http-parser-js@0.5.9", "", {}, "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw=="], - - "http-proxy": ["http-proxy@1.18.1", "", { "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="], - - "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - - "http-proxy-middleware": ["http-proxy-middleware@3.0.3", "", { "dependencies": { "@types/http-proxy": "^1.17.15", "debug": "^4.3.6", "http-proxy": "^1.18.1", "is-glob": "^4.0.3", "is-plain-object": "^5.0.0", "micromatch": "^4.0.8" } }, "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg=="], - - "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - - "hyperdyperid": ["hyperdyperid@1.2.0", "", {}, "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A=="], - - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - - "icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="], - - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "ignore-walk": ["ignore-walk@7.0.0", "", { "dependencies": { "minimatch": "^9.0.0" } }, "sha512-T4gbf83A4NH95zvhVYZc+qWocBBGlpzUXLPGurJggw/WIOwicfXJChLDP/iBZnN5WqROSu5Bm3hhle4z8a8YGQ=="], - - "image-size": ["image-size@0.5.5", "", { "bin": { "image-size": "bin/image-size.js" } }, "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ=="], - - "immutable": ["immutable@5.1.1", "", {}, "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg=="], - - "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - - "ini": ["ini@5.0.0", "", {}, "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw=="], - - "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="], - - "ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="], - - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - - "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], - - "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], - - "is-network-error": ["is-network-error@1.1.0", "", {}, "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "is-plain-obj": ["is-plain-obj@3.0.0", "", {}, "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="], - - "is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="], - - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], - - "is-what": ["is-what@3.14.1", "", {}, "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="], - - "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], - - "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - - "isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="], - - "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - - "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], - - "istanbul-lib-source-maps": ["istanbul-lib-source-maps@4.0.1", "", { "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" } }, "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw=="], - - "istanbul-reports": ["istanbul-reports@3.1.7", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g=="], - - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - - "jasmine-core": ["jasmine-core@5.7.1", "", {}, "sha512-QnurrtpKsPoixxG2R3d1xP0St/2kcX5oTZyDyQJMY+Vzi/HUlu1kGm+2V8Tz+9lV991leB1l0xcsyz40s9xOOw=="], - - "jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], - - "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], - - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - - "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="], - - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - - "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], - - "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - - "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], - - "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], - - "karma": ["karma@6.4.4", "", { "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", "braces": "^3.0.2", "chokidar": "^3.5.1", "connect": "^3.7.0", "di": "^0.0.1", "dom-serialize": "^2.2.1", "glob": "^7.1.7", "graceful-fs": "^4.2.6", "http-proxy": "^1.18.1", "isbinaryfile": "^4.0.8", "lodash": "^4.17.21", "log4js": "^6.4.1", "mime": "^2.5.2", "minimatch": "^3.0.4", "mkdirp": "^0.5.5", "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", "socket.io": "^4.7.2", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, "bin": { "karma": "bin/karma" } }, "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w=="], - - "karma-chrome-launcher": ["karma-chrome-launcher@3.2.0", "", { "dependencies": { "which": "^1.2.1" } }, "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q=="], - - "karma-coverage": ["karma-coverage@2.2.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.1", "istanbul-reports": "^3.0.5", "minimatch": "^3.0.4" } }, "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A=="], - - "karma-jasmine": ["karma-jasmine@5.1.0", "", { "dependencies": { "jasmine-core": "^4.1.0" }, "peerDependencies": { "karma": "^6.0.0" } }, "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ=="], - - "karma-jasmine-html-reporter": ["karma-jasmine-html-reporter@2.1.0", "", { "peerDependencies": { "jasmine-core": "^4.0.0 || ^5.0.0", "karma": "^6.0.0", "karma-jasmine": "^5.0.0" } }, "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ=="], - - "karma-source-map-support": ["karma-source-map-support@1.4.0", "", { "dependencies": { "source-map-support": "^0.5.5" } }, "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - - "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], - - "launch-editor": ["launch-editor@2.10.0", "", { "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" } }, "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA=="], - - "less": ["less@4.2.2", "", { "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", "tslib": "^2.3.0" }, "optionalDependencies": { "errno": "^0.1.1", "graceful-fs": "^4.1.2", "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", "needle": "^3.1.0", "source-map": "~0.6.0" }, "bin": { "lessc": "bin/lessc" } }, "sha512-tkuLHQlvWUTeQ3doAqnHbNn8T6WX1KA8yvbKG9x4VtKtIjHsVKQZCH11zRgAfbDAXC2UNIg/K9BYAAcEzUIrNg=="], - - "less-loader": ["less-loader@12.2.0", "", { "peerDependencies": { "@rspack/core": "0.x || 1.x", "less": "^3.5.0 || ^4.0.0", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg=="], - - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - - "license-webpack-plugin": ["license-webpack-plugin@4.0.2", "", { "dependencies": { "webpack-sources": "^3.0.0" } }, "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw=="], - - "lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="], - - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="], - - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="], - - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="], - - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="], - - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="], - - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="], - - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="], - - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="], - - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="], - - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="], - - "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - - "listr2": ["listr2@8.2.5", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ=="], - - "lmdb": ["lmdb@3.2.6", "", { "dependencies": { "msgpackr": "^1.11.2", "node-addon-api": "^6.1.0", "node-gyp-build-optional-packages": "5.2.2", "ordered-binary": "^1.5.3", "weak-lru-cache": "^1.2.2" }, "optionalDependencies": { "@lmdb/lmdb-darwin-arm64": "3.2.6", "@lmdb/lmdb-darwin-x64": "3.2.6", "@lmdb/lmdb-linux-arm": "3.2.6", "@lmdb/lmdb-linux-arm64": "3.2.6", "@lmdb/lmdb-linux-x64": "3.2.6", "@lmdb/lmdb-win32-x64": "3.2.6" }, "bin": { "download-lmdb-prebuilds": "bin/download-prebuilds.js" } }, "sha512-SuHqzPl7mYStna8WRotY8XX/EUZBjjv3QyKIByeCLFfC9uXT/OIHByEcA07PzbMfQAM0KYJtLgtpMRlIe5dErQ=="], - - "loader-runner": ["loader-runner@4.3.0", "", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="], - - "loader-utils": ["loader-utils@3.3.1", "", {}, "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg=="], - - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], - - "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], - - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - - "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], - - "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], - - "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], - - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], - - "make-dir": ["make-dir@2.1.0", "", { "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" } }, "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA=="], - - "make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "ssri": "^12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], - - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - - "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], - - "memfs": ["memfs@4.17.0", "", { "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", "tree-dump": "^1.0.1", "tslib": "^2.0.0" } }, "sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg=="], - - "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], - - "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - - "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], - - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - - "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - - "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], - - "mini-css-extract-plugin": ["mini-css-extract-plugin@2.9.2", "", { "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" }, "peerDependencies": { "webpack": "^5.0.0" } }, "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w=="], - - "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], - - "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - - "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], - - "minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^3.0.1" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], - - "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], - - "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], - - "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], - - "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], - - "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], - - "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "msgpackr": ["msgpackr@1.11.2", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g=="], - - "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], - - "multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="], - - "mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], - - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - - "needle": ["needle@3.3.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, "bin": { "needle": "bin/needle" } }, "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q=="], - - "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], - - "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], - - "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], - - "node-forge": ["node-forge@1.3.1", "", {}, "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="], - - "node-gyp": ["node-gyp@11.2.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^14.0.3", "nopt": "^8.0.0", "proc-log": "^5.0.0", "semver": "^7.3.5", "tar": "^7.4.3", "tinyglobby": "^0.2.12", "which": "^5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-T0S1zqskVUSxcsSTkAsLc7xCycrRYmtDHadDinzocrThjyQCn5kMlEBSj6H4qDbgsIOSLmmlRIeb0lZXj+UArA=="], - - "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], - - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], - - "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], - - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - - "normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="], - - "npm-bundled": ["npm-bundled@4.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^4.0.0" } }, "sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA=="], - - "npm-install-checks": ["npm-install-checks@7.1.1", "", { "dependencies": { "semver": "^7.1.1" } }, "sha512-u6DCwbow5ynAX5BdiHQ9qvexme4U3qHW3MWe5NqH+NeBm0LbiH6zvGjNNew1fY+AZZUtVHbOPF3j7mJxbUzpXg=="], - - "npm-normalize-package-bin": ["npm-normalize-package-bin@4.0.0", "", {}, "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w=="], - - "npm-package-arg": ["npm-package-arg@12.0.2", "", { "dependencies": { "hosted-git-info": "^8.0.0", "proc-log": "^5.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^6.0.0" } }, "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA=="], - - "npm-packlist": ["npm-packlist@9.0.0", "", { "dependencies": { "ignore-walk": "^7.0.0" } }, "sha512-8qSayfmHJQTx3nJWYbbUmflpyarbLMBc6LCAjYsiGtXxDB68HaZpb8re6zeaLGxZzDuMdhsg70jryJe+RrItVQ=="], - - "npm-pick-manifest": ["npm-pick-manifest@10.0.0", "", { "dependencies": { "npm-install-checks": "^7.1.0", "npm-normalize-package-bin": "^4.0.0", "npm-package-arg": "^12.0.0", "semver": "^7.3.5" } }, "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ=="], - - "npm-registry-fetch": ["npm-registry-fetch@18.0.2", "", { "dependencies": { "@npmcli/redact": "^3.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^14.0.0", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^12.0.0", "proc-log": "^5.0.0" } }, "sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ=="], - - "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - - "obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="], - - "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], - - "on-headers": ["on-headers@1.0.2", "", {}, "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="], - - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - - "open": ["open@10.1.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw=="], - - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], - - "ordered-binary": ["ordered-binary@1.5.3", "", {}, "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA=="], - - "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - - "p-map": ["p-map@7.0.3", "", {}, "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA=="], - - "p-retry": ["p-retry@6.2.1", "", { "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", "retry": "^0.13.1" } }, "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ=="], - - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - - "pacote": ["pacote@20.0.0", "", { "dependencies": { "@npmcli/git": "^6.0.0", "@npmcli/installed-package-contents": "^3.0.0", "@npmcli/package-json": "^6.0.0", "@npmcli/promise-spawn": "^8.0.0", "@npmcli/run-script": "^9.0.0", "cacache": "^19.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^12.0.0", "npm-packlist": "^9.0.0", "npm-pick-manifest": "^10.0.0", "npm-registry-fetch": "^18.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "sigstore": "^3.0.0", "ssri": "^12.0.0", "tar": "^6.1.11" }, "bin": { "pacote": "bin/index.js" } }, "sha512-pRjC5UFwZCgx9kUFDVM9YEahv4guZ1nSLqwmWiLUnDbGsjs+U5w7z6Uc8HNR1a6x8qnu5y9xtGE6D1uAuYz+0A=="], - - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - - "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], - - "parse-node-version": ["parse-node-version@1.0.1", "", {}, "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA=="], - - "parse5": ["parse5@7.2.1", "", { "dependencies": { "entities": "^4.5.0" } }, "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ=="], - - "parse5-html-rewriting-stream": ["parse5-html-rewriting-stream@7.0.0", "", { "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", "parse5-sax-parser": "^7.0.0" } }, "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg=="], - - "parse5-sax-parser": ["parse5-sax-parser@7.0.0", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg=="], - - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], - - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - - "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], - - "path-type": ["path-type@6.0.0", "", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], - - "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], - - "piscina": ["piscina@4.8.0", "", { "optionalDependencies": { "@napi-rs/nice": "^1.0.1" } }, "sha512-EZJb+ZxDrQf3dihsUL7p42pjNyrNIFJCrRHPMgxu/svsj+P3xS3fuEWp7k2+rfsavfl1N0G29b1HGs7J0m8rZA=="], - - "pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="], - - "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], - - "postcss-loader": ["postcss-loader@8.1.1", "", { "dependencies": { "cosmiconfig": "^9.0.0", "jiti": "^1.20.0", "semver": "^7.5.4" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ=="], - - "postcss-media-query-parser": ["postcss-media-query-parser@0.2.3", "", {}, "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig=="], - - "postcss-modules-extract-imports": ["postcss-modules-extract-imports@3.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q=="], - - "postcss-modules-local-by-default": ["postcss-modules-local-by-default@4.2.0", "", { "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw=="], - - "postcss-modules-scope": ["postcss-modules-scope@3.2.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA=="], - - "postcss-modules-values": ["postcss-modules-values@4.0.0", "", { "dependencies": { "icss-utils": "^5.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ=="], - - "postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], - - "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], - - "proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], - - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], - - "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], - - "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], - - "prr": ["prr@1.0.1", "", {}, "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "qjobs": ["qjobs@1.2.0", "", {}, "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg=="], - - "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - - "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], - - "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - - "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], - - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - - "reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="], - - "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], - - "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="], - - "regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="], - - "regenerator-transform": ["regenerator-transform@0.15.2", "", { "dependencies": { "@babel/runtime": "^7.8.4" } }, "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg=="], - - "regex-parser": ["regex-parser@2.3.1", "", {}, "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ=="], - - "regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="], - - "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], - - "regjsparser": ["regjsparser@0.12.0", "", { "dependencies": { "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - - "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], - - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - - "resolve-url-loader": ["resolve-url-loader@5.0.0", "", { "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", "loader-utils": "^2.0.0", "postcss": "^8.2.14", "source-map": "0.6.1" } }, "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg=="], - - "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], - - "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - - "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - - "rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="], - - "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], - - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], - - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - - "sass": ["sass@1.85.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww=="], - - "sass-loader": ["sass-loader@16.0.5", "", { "dependencies": { "neo-async": "^2.6.2" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "node-sass", "sass", "sass-embedded", "webpack"] }, "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw=="], - - "sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], - - "schema-utils": ["schema-utils@4.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g=="], - - "select-hose": ["select-hose@2.0.0", "", {}, "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg=="], - - "selfsigned": ["selfsigned@2.4.1", "", { "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" } }, "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q=="], - - "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], - - "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], - - "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - - "serve-index": ["serve-index@1.9.1", "", { "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", "http-errors": "~1.6.2", "mime-types": "~2.1.17", "parseurl": "~1.3.2" } }, "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw=="], - - "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], - - "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], - - "shallow-clone": ["shallow-clone@3.0.1", "", { "dependencies": { "kind-of": "^6.0.2" } }, "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA=="], - - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - - "shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="], - - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], - - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], - - "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], - - "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "sigstore": ["sigstore@3.1.0", "", { "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", "@sigstore/protobuf-specs": "^0.4.0", "@sigstore/sign": "^3.1.0", "@sigstore/tuf": "^3.1.0", "@sigstore/verify": "^2.1.0" } }, "sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q=="], - - "slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="], - - "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], - - "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - - "socket.io": ["socket.io@4.8.1", "", { "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg=="], - - "socket.io-adapter": ["socket.io-adapter@2.5.5", "", { "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" } }, "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg=="], - - "socket.io-parser": ["socket.io-parser@4.2.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew=="], - - "sockjs": ["sockjs@0.3.24", "", { "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ=="], - - "socks": ["socks@2.8.4", "", { "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ=="], - - "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], - - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "source-map-loader": ["source-map-loader@5.0.0", "", { "dependencies": { "iconv-lite": "^0.6.3", "source-map-js": "^1.0.2" }, "peerDependencies": { "webpack": "^5.72.1" } }, "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA=="], - - "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], - - "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], - - "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], - - "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], - - "spdx-license-ids": ["spdx-license-ids@3.0.21", "", {}, "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg=="], - - "spdy": ["spdy@4.0.2", "", { "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", "select-hose": "^2.0.0", "spdy-transport": "^3.0.0" } }, "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA=="], - - "spdy-transport": ["spdy-transport@3.0.0", "", { "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", "hpack.js": "^2.1.6", "obuf": "^1.1.2", "readable-stream": "^3.0.6", "wbuf": "^1.7.3" } }, "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw=="], - - "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], - - "ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], - - "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], - - "streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="], - - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - - "symbol-observable": ["symbol-observable@4.0.0", "", {}, "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ=="], - - "tailwindcss": ["tailwindcss@4.1.1", "", {}, "sha512-QNbdmeS979Efzim2g/bEvfuh+fTcIdp1y7gA+sb6OYSW74rt7Cr7M78AKdf6HqWT3d5AiTb7SwTT3sLQxr4/qw=="], - - "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], - - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - - "terser": ["terser@5.39.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw=="], - - "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], - - "thingies": ["thingies@1.21.0", "", { "peerDependencies": { "tslib": "^2" } }, "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g=="], - - "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], - - "tinyglobby": ["tinyglobby@0.2.12", "", { "dependencies": { "fdir": "^6.4.3", "picomatch": "^4.0.2" } }, "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww=="], - - "tmp": ["tmp@0.2.3", "", {}, "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - - "tree-dump": ["tree-dump@1.0.2", "", { "peerDependencies": { "tslib": "2" } }, "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ=="], - - "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "tuf-js": ["tuf-js@3.0.1", "", { "dependencies": { "@tufjs/models": "3.0.1", "debug": "^4.3.6", "make-fetch-happen": "^14.0.1" } }, "sha512-+68OP1ZzSF84rTckf3FA95vJ1Zlx/uaXyiiKyPd1pA4rZNkpEvDAKmsu1xUSmbF/chCRYgZ6UZkDwC7PmzmAyA=="], - - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - - "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], - - "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], - - "typed-assert": ["typed-assert@1.0.9", "", {}, "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg=="], - - "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], - - "typescript-eslint": ["typescript-eslint@8.33.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.33.1", "@typescript-eslint/parser": "8.33.1", "@typescript-eslint/utils": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A=="], - - "ua-parser-js": ["ua-parser-js@0.7.40", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ=="], - - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - - "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], - - "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], - - "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.0", "", {}, "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg=="], - - "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.1.0", "", {}, "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w=="], - - "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], - - "unique-filename": ["unique-filename@4.0.0", "", { "dependencies": { "unique-slug": "^5.0.0" } }, "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ=="], - - "unique-slug": ["unique-slug@5.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg=="], - - "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - - "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - - "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - - "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], - - "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], - - "validate-npm-package-name": ["validate-npm-package-name@6.0.0", "", {}, "sha512-d7KLgL1LD3U3fgnvWEY1cQXoO/q6EQ1BSz48Sa149V/5zVTAbgmZIpyI8TRi6U9/JNyeYLlTKsEMPtLC27RFUg=="], - - "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - - "vite": ["vite@6.2.4", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw=="], - - "void-elements": ["void-elements@2.0.1", "", {}, "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung=="], - - "watchpack": ["watchpack@2.4.2", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw=="], - - "wbuf": ["wbuf@1.7.3", "", { "dependencies": { "minimalistic-assert": "^1.0.0" } }, "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="], - - "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], - - "weak-lru-cache": ["weak-lru-cache@1.2.2", "", {}, "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw=="], - - "webpack": ["webpack@5.98.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA=="], - - "webpack-dev-middleware": ["webpack-dev-middleware@7.4.2", "", { "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", "mime-types": "^2.1.31", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"] }, "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA=="], - - "webpack-dev-server": ["webpack-dev-server@5.2.0", "", { "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", "@types/express": "^4.17.21", "@types/serve-index": "^1.9.4", "@types/serve-static": "^1.15.5", "@types/sockjs": "^0.3.36", "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.2.1", "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "express": "^4.21.2", "graceful-fs": "^4.2.6", "http-proxy-middleware": "^2.0.7", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", "p-retry": "^6.2.0", "schema-utils": "^4.2.0", "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^7.4.2", "ws": "^8.18.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"], "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" } }, "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA=="], - - "webpack-merge": ["webpack-merge@6.0.1", "", { "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", "wildcard": "^2.0.1" } }, "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg=="], - - "webpack-sources": ["webpack-sources@3.2.3", "", {}, "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="], - - "webpack-subresource-integrity": ["webpack-subresource-integrity@5.1.0", "", { "dependencies": { "typed-assert": "^1.0.8" }, "peerDependencies": { "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", "webpack": "^5.12.0" }, "optionalPeers": ["html-webpack-plugin"] }, "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q=="], - - "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="], - - "websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="], - - "which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], - - "wildcard": ["wildcard@2.0.1", "", {}, "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - - "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], - - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - - "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - - "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], - - "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "yoctocolors-cjs": ["yoctocolors-cjs@2.1.2", "", {}, "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA=="], - - "zone.js": ["zone.js@0.15.0", "", {}, "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA=="], - - "@angular-devkit/architect/rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="], - - "@angular-devkit/build-angular/postcss": ["postcss@8.5.2", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA=="], - - "@angular-devkit/build-angular/rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="], - - "@angular-devkit/build-webpack/rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="], - - "@angular-devkit/core/rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="], - - "@angular-devkit/core/source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="], - - "@angular-devkit/schematics/rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="], - - "@angular-eslint/schematics/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - - "@angular-eslint/schematics/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "@angular/compiler-cli/@babel/core": ["@babel/core@7.26.9", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.9", "@babel/types": "^7.26.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw=="], - - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/plugin-transform-classes/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], - - "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/preset-env/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/traverse/@babel/generator": ["@babel/generator@7.27.0", "", { "dependencies": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw=="], - - "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@eslint/eslintrc/ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], - - "@inquirer/checkbox/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/confirm/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/core/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/core/mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="], - - "@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], - - "@inquirer/editor/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/expand/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/input/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/number/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/password/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/rawlist/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/search/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@inquirer/select/@inquirer/type": ["@inquirer/type@3.0.5", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg=="], - - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "@npmcli/git/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "@npmcli/git/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - - "@npmcli/package-json/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], - - "@npmcli/package-json/json-parse-even-better-errors": ["json-parse-even-better-errors@4.0.0", "", {}, "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA=="], - - "@npmcli/promise-spawn/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - - "@npmcli/run-script/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - - "@parcel/watcher/node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], - - "@tailwindcss/node/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], - - "@tufjs/models/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1" } }, "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.33.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ=="], - - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - - "@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1" } }, "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA=="], - - "@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA=="], - - "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.33.0", "", { "dependencies": { "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.33.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ=="], - - "@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.33.0", "", { "dependencies": { "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ=="], - - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - - "adjust-sourcemap-loader/loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], - - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - - "cacache/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], - - "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "cacache/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], - - "cli-truncate/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "clone-deep/is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="], - - "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "engine.io/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - - "engine.io/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - - "engine.io/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="], - - "ent/punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="], - - "eslint/ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "express/finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], - - "external-editor/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - - "external-editor/tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], - - "finalhandler/on-finished": ["on-finished@2.3.0", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww=="], - - "finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - - "globby/ignore": ["ignore@7.0.3", "", {}, "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA=="], - - "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "hpack.js/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - - "http-proxy/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], - - "ignore-walk/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "istanbul-lib-report/make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], - - "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "karma/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "karma/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], - - "karma-coverage/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], - - "karma-jasmine/jasmine-core": ["jasmine-core@4.6.1", "", {}, "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ=="], - - "less/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - - "lightningcss/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], - - "log-update/ansi-escapes": ["ansi-escapes@7.0.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw=="], - - "log-update/cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], - - "log-update/slice-ansi": ["slice-ansi@7.1.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg=="], - - "log-update/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "make-dir/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], - - "make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "node-gyp/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], - - "node-gyp/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - - "node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], - - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "pkg-dir/find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="], - - "promise-retry/retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], - - "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], - - "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - - "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], - - "resolve-url-loader/loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], - - "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - - "rollup/@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], - - "schema-utils/ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], - - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], - - "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - - "serve-index/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "serve-index/http-errors": ["http-errors@1.6.3", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", "statuses": ">= 1.4.0 < 2" } }, "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A=="], - - "slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="], - - "socket.io/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - - "socket.io-adapter/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - - "socket.io-adapter/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="], - - "socket.io-parser/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - - "tar/fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], - - "tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], - - "tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], - - "tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], - - "typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.33.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/typescript-estree": "8.33.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ=="], - - "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], - - "webpack-dev-server/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "webpack-dev-server/http-proxy-middleware": ["http-proxy-middleware@2.0.7", "", { "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", "micromatch": "^4.0.2" }, "peerDependencies": { "@types/express": "^4.17.13" }, "optionalPeers": ["@types/express"] }, "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA=="], - - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "@angular/compiler-cli/@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "@angular/compiler-cli/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "@npmcli/git/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - - "@npmcli/package-json/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@npmcli/promise-spawn/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - - "@npmcli/run-script/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - - "@tufjs/models/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/types": "^8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/types": "^8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1" } }, "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "cacache/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "cacache/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - - "cacache/tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - - "cacache/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - - "cli-truncate/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], - - "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "hpack.js/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - - "hpack.js/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], - - "ignore-walk/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "karma-coverage/istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "karma/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "karma/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "karma/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], - - "karma/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - - "log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], - - "log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.0.0", "", { "dependencies": { "get-east-asian-width": "^1.0.0" } }, "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA=="], - - "log-update/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "node-gyp/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - - "node-gyp/tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - - "node-gyp/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - - "node-gyp/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - - "pkg-dir/find-up/locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], - - "pkg-dir/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], - - "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], - - "serve-index/http-errors/inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="], - - "serve-index/http-errors/setprototypeof": ["setprototypeof@1.1.0", "", {}, "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="], - - "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - - "tar/fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "typescript-eslint/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.33.1", "", { "dependencies": { "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1" } }, "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.33.1", "", {}, "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.33.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/types": "8.33.1", "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA=="], - - "webpack-dev-server/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "webpack-dev-server/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], - - "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], - - "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "@npmcli/package-json/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/types": "^8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/type-utils/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "karma/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "karma/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "log-update/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], - - "pkg-dir/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], - - "typescript-eslint/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.33.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/types": "^8.33.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.33.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "webpack-dev-server/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], - - "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "pkg-dir/find-up/locate-path/p-locate/p-limit/yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="], - } -} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js deleted file mode 100644 index 99a007a..0000000 --- a/frontend/eslint.config.js +++ /dev/null @@ -1,43 +0,0 @@ -// @ts-check -const eslint = require("@eslint/js"); -const tseslint = require("typescript-eslint"); -const angular = require("angular-eslint"); - -module.exports = tseslint.config( - { - files: ["**/*.ts"], - extends: [ - eslint.configs.recommended, - ...tseslint.configs.recommended, - ...tseslint.configs.stylistic, - ...angular.configs.tsRecommended, - ], - processor: angular.processInlineTemplates, - rules: { - "@angular-eslint/directive-selector": [ - "error", - { - type: "attribute", - prefix: "app", - style: "camelCase", - }, - ], - "@angular-eslint/component-selector": [ - "error", - { - type: "element", - prefix: "app", - style: "kebab-case", - }, - ], - }, - }, - { - files: ["**/*.html"], - extends: [ - ...angular.configs.templateRecommended, - ...angular.configs.templateAccessibility, - ], - rules: {}, - } -); diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index fd5c806..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "trustworthy-casino", - "version": "0.0.0", - "scripts": { - "ng": "bunx @angular/cli", - "start": "bunx @angular/cli serve --proxy-config src/proxy.conf.json", - "build": "bunx @angular/cli build", - "watch": "bunx @angular/cli build --watch --configuration development", - "test": "bunx @angular/cli test", - "format": "prettier --write \"src/**/*.{ts,html,css,scss}\"", - "format:check": "prettier --check \"src/**/*.{ts,html,css,scss}\"", - "lint": "bunx @angular/cli lint", - "oxlint": "bunx oxlint --deny-warnings" - }, - "private": true, - "dependencies": { - "@angular/animations": "^19.0.0", - "@angular/cdk": "~19.2.0", - "@angular/common": "^19.0.0", - "@angular/compiler": "^19.2.4", - "@angular/core": "^19.0.0", - "@angular/forms": "^19.0.0", - "@angular/platform-browser": "^19.0.0", - "@angular/platform-browser-dynamic": "^19.0.0", - "@angular/router": "^19.0.0", - "@fortawesome/angular-fontawesome": "^1.0.0", - "@fortawesome/fontawesome-svg-core": "^6.7.2", - "@fortawesome/free-brands-svg-icons": "^6.7.2", - "@fortawesome/free-solid-svg-icons": "^6.7.2", - "@stripe/stripe-js": "^7.0.0", - "@tailwindcss/postcss": "^4.0.3", - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "countup.js": "^2.8.0", - "gsap": "^3.12.7", - "postcss": "^8.5.1", - "rxjs": "~7.8.2", - "tailwindcss": "^4.0.3", - "tslib": "^2.3.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^19.0.0", - "@angular/cli": "^19.2.5", - "@angular/compiler-cli": "^19.0.0", - "@types/jasmine": "~5.1.0", - "angular-eslint": "19.7.0", - "eslint": "^9.25.1", - "jasmine-core": "~5.7.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", - "prettier": "^3.4.2", - "typescript": "~5.8.0", - "typescript-eslint": "8.33.1" - } -} diff --git a/frontend/public/blackjack.webp b/frontend/public/blackjack.webp deleted file mode 100644 index e47c246..0000000 Binary files a/frontend/public/blackjack.webp and /dev/null differ diff --git a/frontend/public/coinflip.png b/frontend/public/coinflip.png deleted file mode 100644 index 0f39ca8..0000000 Binary files a/frontend/public/coinflip.png and /dev/null differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index 0a22de4..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/public/images/1-box.png b/frontend/public/images/1-box.png deleted file mode 100644 index b343dbd..0000000 Binary files a/frontend/public/images/1-box.png and /dev/null differ diff --git a/frontend/public/images/2-box.png b/frontend/public/images/2-box.png deleted file mode 100644 index 0ec4438..0000000 Binary files a/frontend/public/images/2-box.png and /dev/null differ diff --git a/frontend/public/images/3-box.png b/frontend/public/images/3-box.png deleted file mode 100644 index 87a8401..0000000 Binary files a/frontend/public/images/3-box.png and /dev/null differ diff --git a/frontend/public/liars-dice.webp b/frontend/public/liars-dice.webp deleted file mode 100644 index 0e1a05c..0000000 Binary files a/frontend/public/liars-dice.webp and /dev/null differ diff --git a/frontend/public/lootbox.webp b/frontend/public/lootbox.webp deleted file mode 100644 index 0750897..0000000 Binary files a/frontend/public/lootbox.webp and /dev/null differ diff --git a/frontend/public/plinko.webp b/frontend/public/plinko.webp deleted file mode 100644 index ada7958..0000000 Binary files a/frontend/public/plinko.webp and /dev/null differ diff --git a/frontend/public/silent-check-sso.html b/frontend/public/silent-check-sso.html deleted file mode 100644 index 9de338b..0000000 --- a/frontend/public/silent-check-sso.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frontend/public/slots.webp b/frontend/public/slots.webp deleted file mode 100644 index 12a8d8e..0000000 Binary files a/frontend/public/slots.webp and /dev/null differ diff --git a/frontend/public/sounds/bet.mp3 b/frontend/public/sounds/bet.mp3 deleted file mode 100644 index b3b7ca3..0000000 Binary files a/frontend/public/sounds/bet.mp3 and /dev/null differ diff --git a/frontend/public/sounds/coinflip.mp3 b/frontend/public/sounds/coinflip.mp3 deleted file mode 100644 index f8708ea..0000000 Binary files a/frontend/public/sounds/coinflip.mp3 and /dev/null differ diff --git a/frontend/public/sounds/drag.mp3 b/frontend/public/sounds/drag.mp3 deleted file mode 100644 index cc7a53d..0000000 Binary files a/frontend/public/sounds/drag.mp3 and /dev/null differ diff --git a/frontend/public/sounds/win.mp3 b/frontend/public/sounds/win.mp3 deleted file mode 100644 index 09441ef..0000000 Binary files a/frontend/public/sounds/win.mp3 and /dev/null differ diff --git a/frontend/src/app/app.component.css b/frontend/src/app/app.component.css deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html deleted file mode 100644 index e07b16d..0000000 --- a/frontend/src/app/app.component.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
- - -
- - - - @if (showLogin() || showRegister() || showRecoverPassword()) { - - - } -
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts deleted file mode 100644 index 7499296..0000000 --- a/frontend/src/app/app.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Component, HostListener, inject, signal } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; -import { NavbarComponent } from '@shared/components/navbar/navbar.component'; -import { FooterComponent } from '@shared/components/footer/footer.component'; -import { LoginComponent } from './feature/auth/login/login.component'; -import { RegisterComponent } from './feature/auth/register/register.component'; -import RecoverPasswordComponent from './feature/auth/recover-password/recover-password.component'; -import { PlaySoundDirective } from '@shared/directives/play-sound.directive'; -import { SoundInitializerService } from '@shared/services/sound-initializer.service'; - -@Component({ - selector: 'app-root', - standalone: true, - imports: [ - RouterOutlet, - NavbarComponent, - FooterComponent, - LoginComponent, - RegisterComponent, - RecoverPasswordComponent, - ], - templateUrl: './app.component.html', - hostDirectives: [PlaySoundDirective], -}) -export class AppComponent { - private soundInitializer = inject(SoundInitializerService); - - showLogin = signal(false); - showRegister = signal(false); - showRecoverPassword = signal(false); - - constructor() { - this.soundInitializer.initialize(); - } - - @HostListener('document:keydown.escape') - handleEscapeKey() { - this.hideAuthForms(); - } - - showLoginForm() { - this.showLogin.set(true); - this.showRegister.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'hidden'; - } - - showRegisterForm() { - this.showRegister.set(true); - this.showLogin.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'hidden'; - } - - showRecoverPasswordForm() { - this.showRecoverPassword.set(true); - this.showLogin.set(false); - this.showRegister.set(false); - document.body.style.overflow = 'hidden'; - } - - hideAuthForms() { - this.showLogin.set(false); - this.showRegister.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'auto'; - } - - stopPropagation(event: MouseEvent) { - event.stopPropagation(); - } -} diff --git a/frontend/src/app/app.config.ts b/frontend/src/app/app.config.ts deleted file mode 100644 index 679c5e4..0000000 --- a/frontend/src/app/app.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApplicationConfig, provideExperimentalZonelessChangeDetection } from '@angular/core'; -import { provideRouter } from '@angular/router'; -import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; - -import { routes } from './app.routes'; -import { provideHttpClient, withInterceptors } from '@angular/common/http'; -import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; -import { httpInterceptor } from '@shared/interceptor/http.interceptor'; - -export const appConfig: ApplicationConfig = { - providers: [ - provideRouter(routes), - FontAwesomeModule, - provideHttpClient(withInterceptors([httpInterceptor])), - provideExperimentalZonelessChangeDetection(), - provideAnimationsAsync(), - ], -}; diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts deleted file mode 100644 index 88f4fe1..0000000 --- a/frontend/src/app/app.routes.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Routes } from '@angular/router'; -import { LandingComponent } from './feature/landing/landing.component'; -import { authGuard } from './auth.guard'; - -export const routes: Routes = [ - { - path: '', - component: LandingComponent, - }, - { - path: 'home', - loadComponent: () => import('./feature/home/home.component'), - canActivate: [authGuard], - }, - { - path: 'verify', - loadComponent: () => import('./feature/auth/verify-email/verify-email.component'), - }, - { - path: 'recover-password', - loadComponent: () => import('./feature/auth/recover-password/recover-password.component'), - }, - { - path: 'reset-password', - loadComponent: () => import('./feature/auth/recover-password/recover-password.component'), - }, - { - path: 'oauth2/callback', - children: [ - { - path: 'github', - loadComponent: () => import('./feature/auth/oauth2/oauth2-callback.component'), - data: { provider: 'github' }, - }, - { - path: 'google', - loadComponent: () => import('./feature/auth/oauth2/oauth2-callback.component'), - data: { provider: 'google' }, - }, - ], - }, - { - path: 'game', - children: [ - { - path: 'blackjack', - loadComponent: () => import('./feature/game/blackjack/blackjack.component'), - canActivate: [authGuard], - }, - { - path: 'coinflip', - loadComponent: () => import('./feature/game/coinflip/coinflip.component'), - canActivate: [authGuard], - }, - { - path: 'slots', - loadComponent: () => import('./feature/game/slots/slots.component'), - canActivate: [authGuard], - }, - { - path: 'lootboxes', - loadComponent: () => - import('./feature/lootboxes/lootbox-selection/lootbox-selection.component'), - canActivate: [authGuard], - children: [ - { - path: 'open/:id', - loadComponent: () => - import('./feature/lootboxes/lootbox-opening/lootbox-opening.component'), - canActivate: [authGuard], - }, - ], - }, - { - path: 'dice', - loadComponent: () => import('./feature/game/dice/dice.component'), - canActivate: [authGuard], - }, - ], - }, -]; diff --git a/frontend/src/app/auth.guard.ts b/frontend/src/app/auth.guard.ts deleted file mode 100644 index ffb2526..0000000 --- a/frontend/src/app/auth.guard.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { CanActivateFn, Router } from '@angular/router'; -import { inject } from '@angular/core'; -import { AuthService } from '@service/auth.service'; - -export const authGuard: CanActivateFn = async () => { - const authService = inject(AuthService); - const router = inject(Router); - - if (authService.isLoggedIn()) { - return true; - } - - router.navigate(['']); - - return false; -}; diff --git a/frontend/src/app/feature/auth/login/login.component.html b/frontend/src/app/feature/auth/login/login.component.html deleted file mode 100644 index 044742c..0000000 --- a/frontend/src/app/feature/auth/login/login.component.html +++ /dev/null @@ -1,160 +0,0 @@ -
- -
diff --git a/frontend/src/app/feature/auth/login/login.component.ts b/frontend/src/app/feature/auth/login/login.component.ts deleted file mode 100644 index 09c1cdf..0000000 --- a/frontend/src/app/feature/auth/login/login.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Component, EventEmitter, Output, signal } from '@angular/core'; -import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { Router } from '@angular/router'; -import { LoginRequest } from '../../../model/auth/LoginRequest'; -import { AuthService } from '@service/auth.service'; -import { CommonModule } from '@angular/common'; -import { environment } from '@environments/environment'; - -@Component({ - selector: 'app-login', - standalone: true, - imports: [CommonModule, ReactiveFormsModule], - templateUrl: './login.component.html', -}) -export class LoginComponent { - loginForm: FormGroup; - errorMessage = signal(''); - isLoading = signal(false); - @Output() switchForm = new EventEmitter(); - @Output() closeDialog = new EventEmitter(); - @Output() forgotPassword = new EventEmitter(); - - constructor( - private fb: FormBuilder, - private authService: AuthService, - private router: Router - ) { - this.loginForm = this.fb.group({ - usernameOrEmail: ['', [Validators.required]], - password: ['', [Validators.required]], - }); - } - - get form() { - return this.loginForm.controls; - } - - switchToRegister(): void { - this.switchForm.emit(); - } - - onSubmit(): void { - if (this.loginForm.invalid) { - return; - } - - this.isLoading.set(true); - this.errorMessage.set(''); - - const loginRequest: LoginRequest = { - usernameOrEmail: this.form['usernameOrEmail'].value, - password: this.form['password'].value, - }; - - this.authService.login(loginRequest).subscribe({ - next: () => { - this.closeDialog.emit(); - this.router.navigate(['/home']); - }, - error: (err) => { - this.isLoading.set(false); - this.errorMessage.set( - err.error?.message || 'Failed to login. Please check your credentials.' - ); - }, - }); - } - - loginWithGithub(): void { - this.isLoading.set(true); - window.location.href = `${environment.apiUrl}/oauth2/github/authorize`; - } - - loginWithGoogle(): void { - this.isLoading.set(true); - window.location.href = `${environment.apiUrl}/oauth2/google/authorize`; - } - - switchToForgotPassword() { - this.forgotPassword.emit(); - } -} diff --git a/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts b/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts deleted file mode 100644 index 9c4bcf3..0000000 --- a/frontend/src/app/feature/auth/oauth2/oauth2-callback.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Component, computed, inject, OnInit, Signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Oauth2Service } from './oauth2.service'; - -@Component({ - selector: 'app-oauth2-callback', - standalone: true, - imports: [CommonModule], - template: ` -
-
-

Authentifizierung...

-
-

{{ error() }}

-
-
- `, -}) -export default class OAuth2CallbackComponent implements OnInit { - error: Signal = computed(() => this.oauthService.error()); - - private route: ActivatedRoute = inject(ActivatedRoute); - private router: Router = inject(Router); - private oauthService: Oauth2Service = inject(Oauth2Service); - - ngOnInit(): void { - this.route.queryParams.subscribe((params) => { - const code = params['code']; - const provider = this.route.snapshot.data['provider'] || 'github'; - - if (code) { - this.oauthService.oauth(provider, code); - } else { - this.oauthService.error.set( - 'Authentifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.' - ); - - setTimeout(() => { - this.router.navigate(['/']); - }, 3000); - } - }); - } -} diff --git a/frontend/src/app/feature/auth/oauth2/oauth2.service.ts b/frontend/src/app/feature/auth/oauth2/oauth2.service.ts deleted file mode 100644 index 79ad6d9..0000000 --- a/frontend/src/app/feature/auth/oauth2/oauth2.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { inject, Injectable, signal } from '@angular/core'; -import { Router } from '@angular/router'; -import { AuthService } from '@service/auth.service'; - -@Injectable({ - providedIn: 'root', -}) -export class Oauth2Service { - private router: Router = inject(Router); - private authService: AuthService = inject(AuthService); - private _error = signal(''); - - oauth(provider: string, code: string) { - const oauth$ = - provider === 'github' ? this.authService.githubAuth(code) : this.authService.googleAuth(code); - - oauth$.subscribe({ - next: () => { - this.router.navigate(['/home']); - }, - error: (err) => { - this._error.set( - err.error?.message || 'Authentifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.' - ); - - setTimeout(() => { - this.router.navigate(['/']); - }, 3000); - }, - }); - } - - public get error() { - return this._error; - } -} diff --git a/frontend/src/app/feature/auth/recover-password/recover-password.component.html b/frontend/src/app/feature/auth/recover-password/recover-password.component.html deleted file mode 100644 index d89ce27..0000000 --- a/frontend/src/app/feature/auth/recover-password/recover-password.component.html +++ /dev/null @@ -1,170 +0,0 @@ - diff --git a/frontend/src/app/feature/auth/recover-password/recover-password.component.ts b/frontend/src/app/feature/auth/recover-password/recover-password.component.ts deleted file mode 100644 index 89f5d96..0000000 --- a/frontend/src/app/feature/auth/recover-password/recover-password.component.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Component, EventEmitter, Output, signal, OnInit } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { ActivatedRoute, Router, RouterModule } from '@angular/router'; -import { AuthService } from '@service/auth.service'; - -@Component({ - selector: 'app-recover-password', - standalone: true, - imports: [CommonModule, ReactiveFormsModule, RouterModule], - templateUrl: './recover-password.component.html', -}) -export default class RecoverPasswordComponent implements OnInit { - emailForm: FormGroup; - resetPasswordForm: FormGroup; - errorMessage = signal(''); - successMessage = signal(''); - isLoading = signal(false); - token = ''; - isResetMode = signal(false); - - @Output() closeDialog = new EventEmitter(); - @Output() switchToLogin = new EventEmitter(); - - constructor( - private fb: FormBuilder, - private authService: AuthService, - private router: Router, - private route: ActivatedRoute - ) { - this.emailForm = this.fb.group({ - email: ['', [Validators.required, Validators.email]], - }); - - this.resetPasswordForm = this.fb.group( - { - password: ['', [Validators.required, Validators.minLength(8)]], - confirmPassword: ['', [Validators.required]], - }, - { - validators: this.passwordMatchValidator, - } - ); - } - - ngOnInit(): void { - // Check if we're in reset mode via URL parameters - // This is still needed for direct access via URLs with token - this.route.queryParamMap.subscribe((params) => { - const token = params.get('token'); - if (token) { - this.token = token; - this.isResetMode.set(true); - } - }); - } - - passwordMatchValidator(form: FormGroup) { - const password = form.get('password')?.value; - const confirmPassword = form.get('confirmPassword')?.value; - return password === confirmPassword ? null : { passwordMismatch: true }; - } - - get emailFormControls() { - return this.emailForm.controls; - } - - get resetFormControls() { - return this.resetPasswordForm.controls; - } - - onSubmitEmail(): void { - if (this.emailForm.invalid) { - return; - } - - this.isLoading.set(true); - this.errorMessage.set(''); - this.successMessage.set(''); - - const email = this.emailFormControls['email'].value; - - this.authService.recoverPassword(email).subscribe({ - next: () => { - this.isLoading.set(false); - this.successMessage.set( - 'Wenn ein Konto mit dieser E-Mail existiert, wird eine E-Mail mit weiteren Anweisungen gesendet.' - ); - this.emailForm.reset(); - setTimeout(() => { - this.closeDialog.emit(); - this.switchToLogin.emit(); - }, 2000); - }, - error: (err) => { - this.isLoading.set(false); - this.errorMessage.set( - err.error?.message || 'Ein Fehler ist aufgetreten. Bitte versuche es später erneut.' - ); - }, - }); - } - - onSubmitReset(): void { - if (this.resetPasswordForm.invalid) { - return; - } - - this.isLoading.set(true); - this.errorMessage.set(''); - this.successMessage.set(''); - - const password = this.resetFormControls['password'].value; - - this.authService.resetPassword(this.token, password).subscribe({ - next: () => { - this.isLoading.set(false); - this.successMessage.set( - 'Dein Passwort wurde erfolgreich zurückgesetzt. Du kannst dich jetzt anmelden.' - ); - setTimeout(() => { - this.closeDialog.emit(); - this.switchToLogin.emit(); - }, 3000); - }, - error: (err) => { - this.isLoading.set(false); - this.errorMessage.set( - err.error?.message || 'Ein Fehler ist aufgetreten. Bitte versuche es später erneut.' - ); - }, - }); - } - - goBackToLogin(): void { - this.switchToLogin.emit(); - } -} diff --git a/frontend/src/app/feature/auth/register/register.component.html b/frontend/src/app/feature/auth/register/register.component.html deleted file mode 100644 index cf342b0..0000000 --- a/frontend/src/app/feature/auth/register/register.component.html +++ /dev/null @@ -1,140 +0,0 @@ -
- -
diff --git a/frontend/src/app/feature/auth/register/register.component.ts b/frontend/src/app/feature/auth/register/register.component.ts deleted file mode 100644 index 8ad38bb..0000000 --- a/frontend/src/app/feature/auth/register/register.component.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Component, EventEmitter, Output, signal } from '@angular/core'; -import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { RegisterRequest } from '../../../model/auth/RegisterRequest'; -import { AuthService } from '@service/auth.service'; -import { CommonModule } from '@angular/common'; -import { HttpErrorResponse } from '@angular/common/http'; - -@Component({ - selector: 'app-register', - standalone: true, - imports: [CommonModule, ReactiveFormsModule], - templateUrl: './register.component.html', -}) -export class RegisterComponent { - registerForm: FormGroup; - errorMessage = signal(''); - isLoading = signal(false); - fieldErrors = signal>({}); - @Output() switchForm = new EventEmitter(); - @Output() closeDialog = new EventEmitter(); - - constructor( - private fb: FormBuilder, - private authService: AuthService - ) { - this.registerForm = this.fb.group({ - email: ['', [Validators.required, Validators.email]], - username: ['', [Validators.required, Validators.minLength(3)]], - password: ['', [Validators.required, Validators.minLength(6)]], - }); - } - - get form() { - return this.registerForm.controls; - } - - switchToLogin(): void { - this.switchForm.emit(); - } - - onSubmit(): void { - if (this.registerForm.invalid) { - return; - } - - this.isLoading.set(true); - this.errorMessage.set(''); - this.fieldErrors.set({}); - - const registerRequest: RegisterRequest = { - email: this.form['email'].value, - username: this.form['username'].value, - password: this.form['password'].value, - }; - - this.authService.register(registerRequest).subscribe({ - next: () => { - this.isLoading.set(false); - this.closeDialog.emit(); - this.switchToLogin(); - }, - error: (err: HttpErrorResponse) => { - this.isLoading.set(false); - - if (err.status === 409) { - const message = err.error?.message; - switch (message) { - case 'Email is already in use': - this.fieldErrors.update((errors) => ({ - ...errors, - email: 'Diese E-Mail-Adresse wird bereits verwendet.', - })); - break; - case 'Username is already taken': - this.fieldErrors.update((errors) => ({ - ...errors, - username: 'Dieser Benutzername ist bereits vergeben.', - })); - break; - } - } else { - this.errorMessage.set(err.error?.message || 'Failed to register. Please try again.'); - } - }, - }); - } -} diff --git a/frontend/src/app/feature/auth/verify-email/verify-email.component.html b/frontend/src/app/feature/auth/verify-email/verify-email.component.html deleted file mode 100644 index d7bc11c..0000000 --- a/frontend/src/app/feature/auth/verify-email/verify-email.component.html +++ /dev/null @@ -1 +0,0 @@ -

Verifying...

diff --git a/frontend/src/app/feature/auth/verify-email/verify-email.component.ts b/frontend/src/app/feature/auth/verify-email/verify-email.component.ts deleted file mode 100644 index 54f4c2f..0000000 --- a/frontend/src/app/feature/auth/verify-email/verify-email.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { AuthService } from '@service/auth.service'; - -@Component({ - selector: 'app-verify-email', - imports: [], - templateUrl: './verify-email.component.html', -}) -export default class VerifyEmailComponent implements OnInit { - route: ActivatedRoute = inject(ActivatedRoute); - router: Router = inject(Router); - authService: AuthService = inject(AuthService); - - ngOnInit(): void { - const token = this.route.snapshot.queryParamMap.get('email-token'); - - if (!token) { - this.router.navigate(['/']); - console.log('no token'); - return; - } - - this.authService.verifyEmail(token).subscribe(() => { - this.router.navigate(['/'], { - queryParams: { login: true }, - }); - }); - } -} diff --git a/frontend/src/app/feature/deposit/deposit.component.html b/frontend/src/app/feature/deposit/deposit.component.html deleted file mode 100644 index e8e4dfb..0000000 --- a/frontend/src/app/feature/deposit/deposit.component.html +++ /dev/null @@ -1,25 +0,0 @@ -@if (isOpen) { - -} diff --git a/frontend/src/app/feature/deposit/deposit.component.ts b/frontend/src/app/feature/deposit/deposit.component.ts deleted file mode 100644 index 8768bbe..0000000 --- a/frontend/src/app/feature/deposit/deposit.component.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - AfterViewInit, - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - ElementRef, - EventEmitter, - inject, - Input, - OnChanges, - OnDestroy, - OnInit, - Output, - SimpleChanges, - ViewChild, -} from '@angular/core'; -import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { loadStripe, Stripe } from '@stripe/stripe-js'; -import { debounceTime } from 'rxjs'; -import { CommonModule } from '@angular/common'; -import gsap from 'gsap'; -import { DepositService } from '@service/deposit.service'; -import { environment } from '@environments/environment'; -import { ModalAnimationService } from '@shared/services/modal-animation.service'; - -@Component({ - selector: 'app-deposit', - standalone: true, - imports: [ReactiveFormsModule, CommonModule], - templateUrl: './deposit.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class DepositComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges { - @Input() isOpen = false; - @Output() closeModalEmitter = new EventEmitter(); - @ViewChild('modalBg') modalBg!: ElementRef; - @ViewChild('modalCard') modalCard!: ElementRef; - protected form!: FormGroup; - protected errorMsg = ''; - private stripe: Stripe | null = null; - private service: DepositService = inject(DepositService); - private modalAnimationService: ModalAnimationService = inject(ModalAnimationService); - private cdr: ChangeDetectorRef = inject(ChangeDetectorRef); - - async ngOnInit() { - this.form = new FormGroup({ - amount: new FormControl(50, [Validators.min(50)]), - }); - - this.form.controls['amount'].valueChanges.pipe(debounceTime(1000)).subscribe((value) => { - if (value < 50) { - this.errorMsg = 'Minimum Einzahlungsbetrag ist 50€'; - } - }); - - this.stripe = await loadStripe(environment.STRIPE_KEY); - } - - ngAfterViewInit() { - if (this.isOpen) { - this.openModal(); - } - } - - ngOnChanges(changes: SimpleChanges) { - if (changes['isOpen']) { - this.cdr.detectChanges(); - setTimeout(() => { - if (this.modalBg?.nativeElement && this.modalCard?.nativeElement) { - if (changes['isOpen'].currentValue) { - this.openModal(); - } else { - this.closeModal(); - } - } - }, 0); - } - } - - ngOnDestroy() { - gsap.killTweensOf([this.modalBg?.nativeElement, this.modalCard?.nativeElement]); - } - - private openModal() { - if (this.modalBg?.nativeElement && this.modalCard?.nativeElement) { - this.modalAnimationService.openModal( - this.modalCard.nativeElement, - this.modalBg.nativeElement - ); - } - } - - submit() { - if (!this.stripe) { - this.errorMsg = 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.'; - return; - } - if (!this.form.valid) { - this.errorMsg = 'Bitte geben Sie einen gültigen Betrag ein.'; - return; - } - - this.service.handleDeposit(this.form.value.amount as number).subscribe(({ sessionId }) => { - this.stripe?.redirectToCheckout({ sessionId }); - }); - } - - public closeModal() { - if (this.modalBg?.nativeElement && this.modalCard?.nativeElement) { - this.modalAnimationService.closeModal( - this.modalCard.nativeElement, - this.modalBg.nativeElement, - () => this.closeModalEmitter.emit() - ); - } - } -} diff --git a/frontend/src/app/feature/game/blackjack/blackjack.component.html b/frontend/src/app/feature/game/blackjack/blackjack.component.html deleted file mode 100644 index 55ad5b1..0000000 --- a/frontend/src/app/feature/game/blackjack/blackjack.component.html +++ /dev/null @@ -1,44 +0,0 @@ -
-
-
- - - - @if (gameInProgress()) { - - } -
- -
- -
-
-
- - - - diff --git a/frontend/src/app/feature/game/blackjack/blackjack.component.ts b/frontend/src/app/feature/game/blackjack/blackjack.component.ts deleted file mode 100644 index e4b19b5..0000000 --- a/frontend/src/app/feature/game/blackjack/blackjack.component.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { Router } from '@angular/router'; -import { DealerHandComponent } from './components/dealer-hand/dealer-hand.component'; -import { PlayerHandComponent } from './components/player-hand/player-hand.component'; -import { GameControlsComponent } from './components/game-controls/game-controls.component'; -import { GameInfoComponent } from './components/game-info/game-info.component'; -import { BlackjackGame, Card } from '@blackjack/models/blackjack.model'; -import { BlackjackService } from '@blackjack/services/blackjack.service'; -import { HttpErrorResponse } from '@angular/common/http'; -import { GameResultComponent } from '@blackjack/components/game-result/game-result.component'; -import { GameState } from '@blackjack/enum/gameState'; -import { UserService } from '@service/user.service'; -import { timer } from 'rxjs'; -import { DebtDialogComponent } from '@shared/components/debt-dialog/debt-dialog.component'; -import { AuthService } from '@service/auth.service'; -import { AudioService } from '@shared/services/audio.service'; - -@Component({ - selector: 'app-blackjack', - standalone: true, - imports: [ - CommonModule, - DealerHandComponent, - PlayerHandComponent, - GameControlsComponent, - GameInfoComponent, - GameResultComponent, - DebtDialogComponent, - ], - templateUrl: './blackjack.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export default class BlackjackComponent implements OnInit { - private router = inject(Router); - private userService = inject(UserService); - private authService = inject(AuthService); - private blackjackService = inject(BlackjackService); - private audioService = inject(AudioService); - - dealerCards = signal([]); - playerCards = signal([]); - currentBet = signal(0); - balance = signal(0); - currentGameId = signal(undefined); - gameInProgress = signal(false); - gameState = signal(GameState.IN_PROGRESS); - showGameResult = signal(false); - - isActionInProgress = signal(false); - - showDebtDialog = signal(false); - debtAmount = signal(0); - - ngOnInit(): void { - // Subscribe to user updates for real-time balance changes - this.authService.userSubject.subscribe((user) => { - if (user) { - this.balance.set(user.balance); - } - }); - } - - private updateGameState(game: BlackjackGame) { - console.log('Game state update:', game); - this.currentGameId.set(game.id); - this.currentBet.set(game.bet); - this.gameInProgress.set(game.state === GameState.IN_PROGRESS); - this.gameState.set(game.state as GameState); - - const isGameOver = game.state !== GameState.IN_PROGRESS; - - this.dealerCards.set( - game.dealerCards.map((card, index) => ({ - ...card, - hidden: !isGameOver && index === 1 && game.state === GameState.IN_PROGRESS, - })) - ); - - this.playerCards.set( - game.playerCards.map((card) => ({ - ...card, - hidden: false, - })) - ); - - if (isGameOver) { - console.log('Game is over, state:', game.state); - this.userService.refreshCurrentUser(); - - // Get the latest balance before showing the result dialog - timer(1000).subscribe(() => { - // Show the result dialog after refreshing user data - timer(500).subscribe(() => { - this.showGameResult.set(true); - if (game.state === GameState.PLAYER_WON || game.state === GameState.PLAYER_BLACKJACK) { - this.audioService.playWinSound(); - } - console.log('Game result dialog shown after delay'); - }); - }); - } - } - - onNewGame(bet: number): void { - this.isActionInProgress.set(true); - this.audioService.playBetSound(); - - this.blackjackService.startGame(bet).subscribe({ - next: (game) => { - this.updateGameState(game); - this.userService.refreshCurrentUser(); - this.isActionInProgress.set(false); - }, - error: (error) => { - console.error('Failed to start game:', error); - this.isActionInProgress.set(false); - }, - }); - } - - onHit(): void { - if (!this.currentGameId() || this.isActionInProgress()) return; - - this.isActionInProgress.set(true); - this.audioService.playBetSound(); - - this.blackjackService.hit(this.currentGameId()!).subscribe({ - next: (game) => { - this.updateGameState(game); - if (game.state !== 'IN_PROGRESS') { - this.userService.refreshCurrentUser(); - } - this.isActionInProgress.set(false); - }, - error: (error) => { - console.error('Failed to hit:', error); - this.handleGameError(error); - this.isActionInProgress.set(false); - }, - }); - } - - onStand(): void { - if (!this.currentGameId() || this.isActionInProgress()) return; - - if (this.gameState() !== GameState.IN_PROGRESS) { - console.log('Cannot stand: game is not in progress'); - return; - } - - this.isActionInProgress.set(true); - this.audioService.playBetSound(); - - this.blackjackService.stand(this.currentGameId()!).subscribe({ - next: (game) => { - this.updateGameState(game); - this.userService.refreshCurrentUser(); - this.isActionInProgress.set(false); - }, - error: (error) => { - console.error('Failed to stand:', error); - this.handleGameError(error); - this.isActionInProgress.set(false); - }, - }); - } - - onDoubleDown(): void { - if (!this.currentGameId() || this.isActionInProgress()) return; - - if (this.gameState() !== GameState.IN_PROGRESS || this.playerCards().length !== 2) { - console.log('Cannot double down: game is not in progress or more than 2 cards'); - return; - } - - this.isActionInProgress.set(true); - this.audioService.playBetSound(); - - this.blackjackService.doubleDown(this.currentGameId()!).subscribe({ - next: (game) => { - this.updateGameState(game); - - // Wait a bit to ensure the backend has finished processing - timer(1000).subscribe(() => { - const user = this.authService.currentUserValue; - if (user && user.balance < 0) { - this.debtAmount.set(Math.abs(user.balance)); - this.showDebtDialog.set(true); - } - }); - - this.isActionInProgress.set(false); - }, - error: (error) => { - console.error('Failed to double down:', error); - this.handleGameError(error); - this.isActionInProgress.set(false); - }, - }); - } - - onCloseGameResult(): void { - console.log('Closing game result dialog'); - this.showGameResult.set(false); - } - - onCloseDebtDialog(): void { - this.showDebtDialog.set(false); - } - - private handleGameError(error: HttpErrorResponse): void { - if (error instanceof HttpErrorResponse) { - if (error.status === 400 && error.error?.error === 'Invalid state') { - this.gameInProgress.set(false); - this.userService.refreshCurrentUser(); - } else if (error.status === 500) { - console.log('Server error occurred. The game may have been updated in another session.'); - this.gameInProgress.set(false); - this.userService.refreshCurrentUser(); - if (this.currentGameId()) { - this.refreshGameState(this.currentGameId()!); - } - } - } - } - - private refreshGameState(gameId: number): void { - this.blackjackService.getGame(gameId).subscribe({ - next: (game) => { - this.updateGameState(game); - }, - error: (err) => { - console.error('Failed to refresh game state:', err); - }, - }); - } - - leaveGame(): void { - this.router.navigate(['/home']); - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts deleted file mode 100644 index 6e61c0e..0000000 --- a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - AfterViewInit, - ChangeDetectionStrategy, - Component, - ElementRef, - Input, - OnChanges, - SimpleChanges, - ViewChild, -} from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { CountUp } from 'countup.js'; - -@Component({ - selector: 'app-animated-number', - standalone: true, - imports: [CommonModule], - template: ` {{ formattedValue }} `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AnimatedNumberComponent implements OnChanges, AfterViewInit { - @Input() value = 0; - @Input() duration = 1; - @Input() ease = 'power1.out'; - - @ViewChild('numberElement') numberElement!: ElementRef; - - private countUp: CountUp | null = null; - private previousValue = 0; - formattedValue = '0,00 €'; - - ngAfterViewInit(): void { - this.initializeCountUp(); - if (this.countUp && this.value !== 0) { - this.countUp.start(() => { - this.previousValue = this.value; - }); - } - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes['value']) { - if (this.countUp) { - const endVal = this.value; - - this.countUp.update(endVal); - this.previousValue = endVal; - } else { - this.formattedValue = new Intl.NumberFormat('de-DE', { - style: 'currency', - currency: 'EUR', - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(this.value); - } - } - } - - private initializeCountUp(): void { - if (this.numberElement) { - this.countUp = new CountUp(this.numberElement.nativeElement, this.value, { - startVal: this.previousValue, - duration: this.duration, - easingFn: (t, b, c, d) => { - if (this.ease === 'power1.out') { - return c * (1 - Math.pow(1 - t / d, 1)) + b; - } - return c * (t / d) + b; - }, - formattingFn: (value) => { - const formatted = new Intl.NumberFormat('de-DE', { - style: 'currency', - currency: 'EUR', - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(value); - this.formattedValue = formatted; - return formatted; - }, - }); - } - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/dealer-hand/dealer-hand.component.ts b/frontend/src/app/feature/game/blackjack/components/dealer-hand/dealer-hand.component.ts deleted file mode 100644 index 3674d63..0000000 --- a/frontend/src/app/feature/game/blackjack/components/dealer-hand/dealer-hand.component.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { Card } from '@blackjack/models/blackjack.model'; -import { PlayingCardComponent } from '../playing-card/playing-card.component'; -import { GameControlsService } from '@blackjack/services/game-controls.service'; - -@Component({ - selector: 'app-dealer-hand', - standalone: true, - imports: [CommonModule, PlayingCardComponent], - template: ` -
-
-

Dealer's Karten

-
-
Punkte:
-
- {{ gameControlsService.calculateHandValue(cards) }} -
-
-
-
-
- @if (cards.length > 0) { - @for (card of cardsWithState; track card.id) { - - } - } @else { -
- Warte auf Spielstart... -
- } -
-
-
- `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class DealerHandComponent implements OnChanges { - @Input() cards: Card[] = []; - cardsWithState: (Card & { isNew: boolean; id: string })[] = []; - - private lastCardCount = 0; - - constructor(protected gameControlsService: GameControlsService) {} - - ngOnChanges(changes: SimpleChanges): void { - if (changes['cards']) { - this.updateCardsWithState(); - } - } - - private updateCardsWithState(): void { - const newCards = this.cards.length > this.lastCardCount; - - this.cardsWithState = this.cards.map((card, index) => { - const isNew = newCards && index >= this.lastCardCount; - - return { - ...card, - isNew, - id: `${card.suit}-${card.rank}-${index}`, - }; - }); - - this.lastCardCount = this.cards.length; - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/game-controls/game-controls.component.ts b/frontend/src/app/feature/game/blackjack/components/game-controls/game-controls.component.ts deleted file mode 100644 index 9799b08..0000000 --- a/frontend/src/app/feature/game/blackjack/components/game-controls/game-controls.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { GameState } from '@blackjack/enum/gameState'; -import { Card } from '@blackjack/models/blackjack.model'; -import { GameControlsService } from '@blackjack/services/game-controls.service'; - -@Component({ - selector: 'app-game-controls', - standalone: true, - imports: [CommonModule], - template: ` -
-
-
-
- Deine Punkte: {{ gameControlsService.calculateHandValue(playerCards) }} -
-
- Status: - {{ - gameControlsService.getStatusText(gameState) - }} -
-
-
-
- - - - -
-
- `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class GameControlsComponent { - @Input() playerCards: Card[] = []; - @Input() gameState: GameState = GameState.IN_PROGRESS; - @Input() isActionInProgress = false; - - @Output() hit = new EventEmitter(); - @Output() stand = new EventEmitter(); - @Output() doubleDown = new EventEmitter(); - @Output() leave = new EventEmitter(); - - protected readonly GameState = GameState; - - constructor(protected gameControlsService: GameControlsService) {} - - get canDoubleDown(): boolean { - return ( - this.gameState === GameState.IN_PROGRESS && - this.playerCards.length === 2 && - !this.isActionInProgress - ); - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts b/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts deleted file mode 100644 index 644fb22..0000000 --- a/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - OnChanges, - Output, - signal, - SimpleChanges, -} from '@angular/core'; -import { CommonModule, CurrencyPipe } from '@angular/common'; -import { FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { BettingService } from '@blackjack/services/betting.service'; -import { AnimatedNumberComponent } from '../animated-number/animated-number.component'; - -@Component({ - selector: 'app-game-info', - standalone: true, - imports: [CommonModule, CurrencyPipe, ReactiveFormsModule, AnimatedNumberComponent], - template: ` -
-

Spiel Informationen

-
-
- Aktuelle Wette: - - - -
- - @if (!gameInProgress) { -
- - - - -
- } - -
-
- - - @if (betForm.get('bet')?.errors?.['required'] && betForm.get('bet')?.touched) { - Bitte geben Sie einen Einsatz ein - } - @if (betForm.get('bet')?.errors?.['min'] && betForm.get('bet')?.touched) { - Mindestens 1€ setzen - } - @if (betForm.get('bet')?.errors?.['max'] && betForm.get('bet')?.touched) { - Nicht genügend Guthaben - } -
- -
-
-
- `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class GameInfoComponent implements OnChanges { - @Input() set balance(value: number) { - this._balance.set(value); - } - get balance() { - return this._balance(); - } - private _balance = signal(0); - - @Input() currentBet = 0; - @Input() gameInProgress = false; - @Input() isActionInProgress = false; - @Output() newGame = new EventEmitter(); - - betForm: FormGroup; - - constructor(private bettingService: BettingService) { - this.betForm = this.bettingService.createBetForm(); - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes['balance']) { - this.bettingService.updateBetFormValidators(this.betForm, this.balance); - } - } - - setBetAmount(percentage: number) { - const betAmount = this.bettingService.calculateBetAmount(this.balance, percentage); - if (this.bettingService.isValidBet(betAmount, this.balance)) { - this.betForm.patchValue({ bet: betAmount }); - } - } - - onSubmit() { - if (this.betForm.valid) { - const betAmount = parseFloat(this.betForm.value.bet); - if (this.bettingService.isValidBet(betAmount, this.balance)) { - this.newGame.emit(betAmount); - this.betForm.reset(); - } - } - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts b/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts deleted file mode 100644 index 1aab1a4..0000000 --- a/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { animate, style, transition, trigger } from '@angular/animations'; -import { GameState } from '../../enum/gameState'; -import { AnimatedNumberComponent } from '../animated-number/animated-number.component'; - -@Component({ - selector: 'app-game-result', - standalone: true, - imports: [CommonModule, AnimatedNumberComponent], - template: ` - - `, - changeDetection: ChangeDetectionStrategy.OnPush, - animations: [ - trigger('fadeInOut', [ - transition(':enter', [ - style({ opacity: 0 }), - animate('150ms ease-out', style({ opacity: 1 })), - ]), - transition(':leave', [animate('150ms ease-in', style({ opacity: 0 }))]), - ]), - trigger('cardAnimation', [ - transition(':enter', [ - style({ opacity: 0, transform: 'scale(0.95)' }), - animate('200ms ease-out', style({ opacity: 1, transform: 'scale(1)' })), - ]), - ]), - ], -}) -export class GameResultComponent { - @Input() gameState: GameState = GameState.IN_PROGRESS; - @Input() amount = 0; - @Input() balance = 0; - @Input() set show(value: boolean) { - console.log('GameResultComponent show input changed:', value, 'gameState:', this.gameState); - this.visible = value; - } - - @Output() gameResultClosed = new EventEmitter(); - - visible = false; - - get isWin(): boolean { - return this.gameState === GameState.PLAYER_WON || this.gameState === GameState.PLAYER_BLACKJACK; - } - - get isLoss(): boolean { - return this.gameState === GameState.PLAYER_LOST; - } - - get isDraw(): boolean { - return this.gameState === GameState.DRAW; - } - - getResultTitle(): string { - if (this.gameState === GameState.PLAYER_BLACKJACK) return 'Blackjack!'; - if (this.isWin) return 'Gewonnen!'; - if (this.isLoss) return 'Verloren!'; - if (this.isDraw) return 'Unentschieden!'; - return ''; - } - - getResultMessage(): string { - if (this.gameState === GameState.PLAYER_BLACKJACK) - return 'Glückwunsch! Du hast mit einem Blackjack gewonnen!'; - if (this.isWin) return 'Glückwunsch! Du hast diese Runde gewonnen.'; - if (this.isLoss) return 'Schade! Du hast diese Runde verloren.'; - if (this.isDraw) return 'Diese Runde endet unentschieden. Dein Einsatz wurde zurückgegeben.'; - return ''; - } - - getResultClass(): string { - if (this.gameState === GameState.PLAYER_BLACKJACK) return 'text-emerald font-bold'; - if (this.isWin) return 'text-emerald'; - if (this.isLoss) return 'text-accent-red'; - if (this.isDraw) return 'text-yellow-400'; - return ''; - } - - closeDialog(): void { - this.visible = false; - this.gameResultClosed.emit(); - console.log('Dialog closed by user'); - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/player-hand/player-hand.component.ts b/frontend/src/app/feature/game/blackjack/components/player-hand/player-hand.component.ts deleted file mode 100644 index bca976c..0000000 --- a/frontend/src/app/feature/game/blackjack/components/player-hand/player-hand.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { PlayingCardComponent } from '../playing-card/playing-card.component'; -import { Card } from '@blackjack/models/blackjack.model'; -import { GameControlsService } from '@blackjack/services/game-controls.service'; - -@Component({ - selector: 'app-player-hand', - standalone: true, - imports: [CommonModule, PlayingCardComponent], - template: ` -
-
-

Deine Karten

-
-
Punkte:
-
- {{ gameControlsService.calculateHandValue(cards) }} -
-
-
-
-
- @if (cards.length > 0) { - @for (card of cardsWithState; track card.id) { - - } - } @else { -
- Platziere eine Wette um zu spielen... -
- } -
-
-
- `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class PlayerHandComponent implements OnChanges { - @Input() cards: Card[] = []; - cardsWithState: (Card & { isNew: boolean; id: string })[] = []; - - private lastCardCount = 0; - - constructor(protected gameControlsService: GameControlsService) {} - - ngOnChanges(changes: SimpleChanges): void { - if (changes['cards']) { - this.updateCardsWithState(); - } - } - - private updateCardsWithState(): void { - const newCards = this.cards.length > this.lastCardCount; - - this.cardsWithState = this.cards.map((card, index) => { - const isNew = newCards && index >= this.lastCardCount; - - return { - ...card, - isNew, - id: `${card.suit}-${card.rank}-${index}`, - }; - }); - - this.lastCardCount = this.cards.length; - } -} diff --git a/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts b/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts deleted file mode 100644 index 0fbbb5a..0000000 --- a/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { - AfterViewInit, - ChangeDetectionStrategy, - Component, - ElementRef, - Input, - OnChanges, - SimpleChanges, -} from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { gsap } from 'gsap'; -import { Suit, suitSymbols } from '@blackjack/models/blackjack.model'; - -@Component({ - selector: 'app-playing-card', - standalone: true, - imports: [CommonModule], - template: ` -
- @if (!hidden) { - {{ - getDisplayRank(rank) - }} - } - @if (!hidden) { - {{ getSuitSymbol(suit) }} - } - @if (!hidden) { - {{ getDisplayRank(rank) }} - } -
- `, - styles: [ - ` - .card-element { - transform-style: preserve-3d; - backface-visibility: hidden; - } - `, - ], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class PlayingCardComponent implements AfterViewInit, OnChanges { - @Input({ required: true }) rank!: string; - @Input({ required: true }) suit!: Suit; - @Input({ required: true }) hidden!: boolean; - @Input() isNew = false; - - constructor(private elementRef: ElementRef) {} - - get isRedSuit(): boolean { - return this.suit === 'HEARTS' || this.suit === 'DIAMONDS'; - } - - ngAfterViewInit(): void { - if (this.isNew) { - this.animateNewCard(); - } - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes['hidden'] && !changes['hidden'].firstChange) { - this.animateCardFlip(); - } - } - - private animateNewCard(): void { - const cardElement = this.elementRef.nativeElement.querySelector('.card-element'); - gsap.fromTo( - cardElement, - { - y: -100, - opacity: 0, - rotation: -10, - scale: 0.7, - }, - { - y: 0, - opacity: 1, - rotation: 0, - scale: 1, - duration: 0.5, - ease: 'power2.out', - } - ); - } - - private animateCardFlip(): void { - const cardElement = this.elementRef.nativeElement.querySelector('.card-element'); - gsap.to(cardElement, { - rotationY: 180, - duration: 0.3, - onComplete: () => { - gsap.set(cardElement, { rotationY: 0 }); - }, - }); - } - - protected getSuitSymbol(suit: Suit): string { - return suitSymbols[suit]; - } - - protected getDisplayRank(rank: string): string { - const rankMap: Record = { - TWO: '2', - THREE: '3', - FOUR: '4', - FIVE: '5', - SIX: '6', - SEVEN: '7', - EIGHT: '8', - NINE: '9', - TEN: '10', - JACK: 'J', - QUEEN: 'Q', - KING: 'K', - ACE: 'A', - }; - return rankMap[rank] || rank; - } -} diff --git a/frontend/src/app/feature/game/blackjack/enum/gameState.ts b/frontend/src/app/feature/game/blackjack/enum/gameState.ts deleted file mode 100644 index 977e16d..0000000 --- a/frontend/src/app/feature/game/blackjack/enum/gameState.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum GameState { - PLAYER_WON = 'PLAYER_WON', - IN_PROGRESS = 'IN_PROGRESS', - PLAYER_LOST = 'PLAYER_LOST', - DRAW = 'DRAW', - PLAYER_BLACKJACK = 'PLAYER_BLACKJACK', -} diff --git a/frontend/src/app/feature/game/blackjack/models/blackjack.model.ts b/frontend/src/app/feature/game/blackjack/models/blackjack.model.ts deleted file mode 100644 index 55f2ee1..0000000 --- a/frontend/src/app/feature/game/blackjack/models/blackjack.model.ts +++ /dev/null @@ -1,23 +0,0 @@ -export type Suit = 'HEARTS' | 'DIAMONDS' | 'CLUBS' | 'SPADES'; - -export interface Card { - suit: Suit; - rank: string; - hidden: boolean; -} - -export interface BlackjackGame { - id: number; - state: string; - bet: number; - playerCards: Card[]; - dealerCards: Card[]; - userId: number; -} - -export const suitSymbols: Record = { - HEARTS: '♥', - DIAMONDS: '♦', - CLUBS: '♣', - SPADES: '♠', -}; diff --git a/frontend/src/app/feature/game/blackjack/models/card.model.ts b/frontend/src/app/feature/game/blackjack/models/card.model.ts deleted file mode 100644 index 79b5ad1..0000000 --- a/frontend/src/app/feature/game/blackjack/models/card.model.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Card { - value: string; - suit: string; - hidden: boolean; -} diff --git a/frontend/src/app/feature/game/blackjack/services/betting.service.ts b/frontend/src/app/feature/game/blackjack/services/betting.service.ts deleted file mode 100644 index 347f19b..0000000 --- a/frontend/src/app/feature/game/blackjack/services/betting.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; - -@Injectable({ - providedIn: 'root', -}) -export class BettingService { - constructor(private fb: FormBuilder) {} - - createBetForm(): FormGroup { - return this.fb.group({ - bet: ['', [Validators.required, Validators.min(1)]], - }); - } - - updateBetFormValidators(form: FormGroup, balance: number): void { - form.reset(); - form - .get('bet') - ?.setValidators([Validators.required, Validators.min(1), Validators.max(balance)]); - form.get('bet')?.updateValueAndValidity(); - } - - calculateBetAmount(balance: number, percentage: number): number { - return Math.floor(balance * percentage * 100) / 100; - } - - isValidBet(betAmount: number, balance: number): boolean { - return betAmount >= 1 && betAmount <= balance; - } -} diff --git a/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts b/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts deleted file mode 100644 index 5e43dc7..0000000 --- a/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { catchError, Observable } from 'rxjs'; -import { BlackjackGame } from '@blackjack/models/blackjack.model'; - -@Injectable({ - providedIn: 'root', -}) -export class BlackjackService { - private http = inject(HttpClient); - - startGame(bet: number): Observable { - return this.http - .post('/backend/blackjack/start', { betAmount: bet }, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Start game error:', error); - throw error; - }) - ); - } - - hit(gameId: number): Observable { - return this.http - .post(`/backend/blackjack/${gameId}/hit`, {}, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Hit error:', error); - throw error; - }) - ); - } - - stand(gameId: number): Observable { - return this.http - .post(`/backend/blackjack/${gameId}/stand`, {}, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Stand error:', error); - throw error; - }) - ); - } - - doubleDown(gameId: number): Observable { - return this.http - .post(`/backend/blackjack/${gameId}/doubleDown`, {}, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Double Down error:', error); - throw error; - }) - ); - } - - getGame(gameId: number): Observable { - return this.http - .get(`/backend/blackjack/${gameId}`, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Get game error:', error); - throw error; - }) - ); - } -} diff --git a/frontend/src/app/feature/game/blackjack/services/game-controls.service.ts b/frontend/src/app/feature/game/blackjack/services/game-controls.service.ts deleted file mode 100644 index fd055c8..0000000 --- a/frontend/src/app/feature/game/blackjack/services/game-controls.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Card } from '../models/blackjack.model'; -import { GameState } from '../enum/gameState'; - -@Injectable({ - providedIn: 'root', -}) -export class GameControlsService { - calculateHandValue(cards: Card[]): number { - let sum = 0; - let aceCount = 0; - - const rankValues: Record = { - TWO: 2, - THREE: 3, - FOUR: 4, - FIVE: 5, - SIX: 6, - SEVEN: 7, - EIGHT: 8, - NINE: 9, - TEN: 10, - JACK: 10, - QUEEN: 10, - KING: 10, - ACE: 11, - }; - - for (const card of cards) { - if (!card.hidden) { - const value = rankValues[card.rank] || 0; - sum += value; - if (card.rank === 'ACE') { - aceCount++; - } - } - } - - while (sum > 21 && aceCount > 0) { - sum -= 10; - aceCount--; - } - - return sum; - } - - getStatusText(state: GameState): string { - switch (state) { - case GameState.IN_PROGRESS: - return 'Spiel läuft'; - case GameState.PLAYER_WON: - return 'Gewonnen!'; - case GameState.PLAYER_LOST: - return 'Verloren!'; - case GameState.DRAW: - return 'Unentschieden!'; - default: - return state; - } - } - - getStatusClass(state: GameState): string { - switch (state) { - case GameState.PLAYER_WON: - return 'text-emerald'; - case GameState.PLAYER_LOST: - return 'text-accent-red'; - case GameState.DRAW: - return 'text-yellow-400'; - default: - return 'text-white'; - } - } -} diff --git a/frontend/src/app/feature/game/coinflip/coinflip.component.css b/frontend/src/app/feature/game/coinflip/coinflip.component.css deleted file mode 100644 index 06c9671..0000000 --- a/frontend/src/app/feature/game/coinflip/coinflip.component.css +++ /dev/null @@ -1,117 +0,0 @@ -/* Custom CSS for 3D Transformations and Coin Flip */ -@keyframes flipToHeads { - 0% { - transform: rotateY(0); - } - 100% { - transform: rotateY(1800deg); /* End with heads facing up (even number of Y rotations) */ - } -} - -@keyframes flipToTails { - 0% { - transform: rotateY(0); - } - 100% { - transform: rotateY(1980deg); /* End with tails facing up (odd number of Y rotations) */ - } -} - -.coin-container { - width: 180px; - height: 180px; - perspective: 1000px; - margin: 20px auto; -} - -.coin { - width: 100%; - height: 100%; - position: relative; - transform-style: preserve-3d; - transition: transform 0.01s; - transform: rotateY(0deg); - box-shadow: 0 0 30px rgba(0, 0, 0, 0.4); -} - -.coin-side { - width: 100%; - height: 100%; - position: absolute; - backface-visibility: hidden; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-weight: bold; - font-size: 24px; - box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.2); - border: 8px solid rgba(255, 255, 255, 0.2); -} - -.front { - background: linear-gradient(45deg, #ffd700, #ffb700); - color: #333; - z-index: 2; - transform: rotateY(0); -} - -.back { - background: linear-gradient(45deg, #5a5a5a, #333333); - color: white; - z-index: 1; - transform: rotateY(180deg); -} - -/* We apply transform directly to the SVG element in HTML */ - -/* Text for both sides */ -.coin-text { - /* Ensure text is readable */ - user-select: none; - pointer-events: none; -} - -/* Animation classes */ -.coin.animate-to-heads { - animation: flipToHeads 1s ease-in-out forwards; -} - -.coin.animate-to-tails { - animation: flipToTails 1s ease-in-out forwards; -} - -/* Make the buttons more responsive */ -button:not([disabled]) { - cursor: pointer; - transition: all 0.2s ease; -} - -button:not([disabled]):hover { - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); -} - -button:not([disabled]):active { - transform: translateY(1px); -} - -/* Animation for results */ -@keyframes popIn { - 0% { - transform: scale(0.8); - opacity: 0; - } - 70% { - transform: scale(1.1); - opacity: 1; - } - 100% { - transform: scale(1); - opacity: 1; - } -} - -.result-text { - animation: popIn 0.5s ease-out forwards; -} diff --git a/frontend/src/app/feature/game/coinflip/coinflip.component.html b/frontend/src/app/feature/game/coinflip/coinflip.component.html deleted file mode 100644 index 8dd6be8..0000000 --- a/frontend/src/app/feature/game/coinflip/coinflip.component.html +++ /dev/null @@ -1,141 +0,0 @@ -
-
-
- - @if (gameResult()) { -
-

- {{ gameResult()?.isWin ? 'Du hast gewonnen!' : 'Du hast verloren' }} -

-

- Münze zeigt: - {{ gameResult()?.coinSide === 'HEAD' ? 'KOPF' : 'ZAHL' }} -

- @if (gameResult()?.isWin) { -

- +{{ gameResult()?.payout | currency: 'EUR' }} -

- } -
- } - - - @if (errorMessage()) { -
-

{{ errorMessage() }}

-
- } - - -
-
- -
-
KOPF
-
- - -
- - ZAHL -
-
-
- - -
- - -
-
- - -
-
-

Spielinformationen

-
- -
- Aktueller Einsatz: - - € - -
- - -
- Dein Guthaben: - - {{ balance() | currency: 'EUR' }} - -
- - - @if (!gameInProgress()) { -
- - - - -
- } - - -
-
- - Darf Guthaben nicht überschreiten -
- -
- - -
-

Spielregeln

-
    -
  • • Wähle deinen Einsatzbetrag
  • -
  • • Wähle Kopf oder Zahl
  • -
  • • Gewinne das Doppelte deines Einsatzes bei richtiger Wahl
  • -
-
-
-
-
-
-
diff --git a/frontend/src/app/feature/game/coinflip/coinflip.component.ts b/frontend/src/app/feature/game/coinflip/coinflip.component.ts deleted file mode 100644 index 112a300..0000000 --- a/frontend/src/app/feature/game/coinflip/coinflip.component.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { NgClass, NgIf, CurrencyPipe, CommonModule } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; -import { FormsModule } from '@angular/forms'; -import { - ChangeDetectionStrategy, - Component, - ElementRef, - inject, - OnInit, - signal, - ViewChild, -} from '@angular/core'; -import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; -import { catchError, finalize } from 'rxjs/operators'; -import { of } from 'rxjs'; -import { AuthService } from '@service/auth.service'; -import { AudioService } from '@shared/services/audio.service'; -import { CoinflipGame, CoinflipRequest } from './models/coinflip.model'; - -@Component({ - selector: 'app-coinflip', - standalone: true, - imports: [AnimatedNumberComponent, CurrencyPipe, FormsModule, CommonModule, NgIf, NgClass], - templateUrl: './coinflip.component.html', - styleUrl: './coinflip.component.css', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export default class CoinflipComponent implements OnInit { - currentBet = signal(10); - balance = signal(0); - gameInProgress = signal(false); - isActionInProgress = signal(false); - gameResult = signal(null); - betInputValue = signal(10); - errorMessage = signal(''); - isInvalidBet = signal(false); - - @ViewChild('coinElement') coinElement?: ElementRef; - - audioService = inject(AudioService); - authService = inject(AuthService); - private http = inject(HttpClient); - - private coinflipSound?: HTMLAudioElement; - - ngOnInit(): void { - // Abonniere Benutzerupdates für Echtzeitaktualisierungen des Guthabens - this.authService.userSubject.subscribe((user) => { - if (user) { - this.balance.set(user.balance); - } - }); - - // Initialisiere Münzwurf-Sound - this.coinflipSound = new Audio('/sounds/coinflip.mp3'); - } - - setBetAmount(percentage: number) { - const newBet = Math.floor(this.balance() * percentage); - this.betInputValue.set(newBet > 0 ? newBet : 1); - this.currentBet.set(this.betInputValue()); - } - - updateBet(event: Event) { - const inputElement = event.target as HTMLInputElement; - let value = Number(inputElement.value); - - // Setze ungültigen Einsatz-Status zurück - this.isInvalidBet.set(false); - - // Erzwinge Mindesteinsatz von 1 - if (value <= 0) { - value = 1; - } - - // Begrenze Einsatz auf verfügbares Guthaben und zeige Feedback - if (value > this.balance()) { - value = this.balance(); - // Visuelles Feedback anzeigen - this.isInvalidBet.set(true); - // Zeige den Fehler kurz an - setTimeout(() => this.isInvalidBet.set(false), 800); - // Aktualisiere das Eingabefeld direkt, um dem Benutzer den maximalen Wert anzuzeigen - inputElement.value = String(value); - } - - // Aktualisiere Signale - this.betInputValue.set(value); - this.currentBet.set(value); - } - - betHeads() { - this.placeBet('HEAD'); - } - - betTails() { - this.placeBet('TAILS'); - } - - private placeBet(side: 'HEAD' | 'TAILS') { - if (this.gameInProgress() || this.isActionInProgress()) return; - - // Setze vorheriges Ergebnis zurück - this.gameResult.set(null); - this.errorMessage.set(''); - - // Setze Spielstatus - this.gameInProgress.set(true); - this.isActionInProgress.set(true); - - // Spiele Einsatz-Sound - this.audioService.playBetSound(); - - // Erstelle Einsatz-Anfrage - const request: CoinflipRequest = { - betAmount: this.currentBet(), - coinSide: side, - }; - - // API aufrufen - this.http - .post('/backend/coinflip', request) - .pipe( - catchError((error) => { - console.error('Fehler beim Spielen von Coinflip:', error); - - if (error.status === 400 && error.error.message.includes('insufficient')) { - this.errorMessage.set('Unzureichendes Guthaben'); - } else { - this.errorMessage.set('Ein Fehler ist aufgetreten. Bitte versuche es erneut.'); - } - - this.gameInProgress.set(false); - return of(null); - }), - finalize(() => { - this.isActionInProgress.set(false); - }) - ) - .subscribe((result) => { - if (!result) return; - - console.log('API-Antwort:', result); - - // Behebe mögliche Inkonsistenzen bei der Eigenschaftenbenennung vom Backend - const fixedResult: CoinflipGame = { - isWin: result.isWin ?? result.win, - payout: result.payout, - coinSide: result.coinSide, - }; - - console.log('Korrigiertes Ergebnis:', fixedResult); - - // Spiele Münzwurf-Animation und -Sound - this.playCoinFlipAnimation(fixedResult.coinSide); - - // Setze Ergebnis nach Abschluss der Animation - setTimeout(() => { - this.gameResult.set(fixedResult); - - // Aktualisiere Guthaben mit neuem Wert vom Auth-Service - this.authService.loadCurrentUser(); - - // Spiele Gewinn-Sound, wenn der Spieler gewonnen hat - if (fixedResult.isWin) { - this.audioService.playWinSound(); - } - - // Setze Spielstatus nach Anzeigen des Ergebnisses zurück - setTimeout(() => { - this.gameInProgress.set(false); - }, 1500); - }, 1100); // Kurz nach Ende der Animation - }); - } - - private playCoinFlipAnimation(result: 'HEAD' | 'TAILS') { - if (!this.coinElement) return; - - const coinEl = this.coinElement.nativeElement; - - // Setze bestehende Animationen zurück - coinEl.classList.remove('animate-to-heads', 'animate-to-tails'); - - // Setze alle Inline-Styles von vorherigen Animationen zurück - coinEl.style.transform = ''; - - // Erzwinge Reflow, um Animation neu zu starten - void coinEl.offsetWidth; - - // Spiele Münzwurf-Sound - if (this.coinflipSound) { - this.coinflipSound.currentTime = 0; - this.coinflipSound - .play() - .catch((err) => console.error('Fehler beim Abspielen des Sounds:', err)); - } - - // Füge passende Animationsklasse basierend auf dem Ergebnis hinzu - if (result === 'HEAD') { - coinEl.classList.add('animate-to-heads'); - } else { - coinEl.classList.add('animate-to-tails'); - } - - console.log(`Animation angewendet für Ergebnis: ${result}`); - } - - /** - * Validiert Eingabe während der Benutzer tippt, um ungültige Werte zu verhindern - */ - validateBetInput(event: KeyboardEvent) { - // Erlaube Navigationstasten (Pfeile, Entf, Rücktaste, Tab) - const navigationKeys = ['ArrowLeft', 'ArrowRight', 'Delete', 'Backspace', 'Tab']; - if (navigationKeys.includes(event.key)) { - return; - } - - // Erlaube nur Zahlen - if (!/^\d$/.test(event.key)) { - event.preventDefault(); - return; - } - - // Ermittle den Wert, der nach dem Tastendruck entstehen würde - const input = event.target as HTMLInputElement; - const currentValue = input.value; - const cursorPosition = input.selectionStart || 0; - const newValue = - currentValue.substring(0, cursorPosition) + - event.key + - currentValue.substring(input.selectionEnd || cursorPosition); - const numValue = Number(newValue); - - // Verhindere Werte, die größer als das Guthaben sind - if (numValue > this.balance()) { - event.preventDefault(); - } - } - - // Der Paste-Handler wurde der Einfachheit halber entfernt, da die updateBet-Methode - // jeden Wert behandelt, der in das Eingabefeld gelangt - - getResultClass() { - if (!this.gameResult()) return ''; - const result = this.gameResult(); - const isWinner = result?.isWin || result?.win; - return isWinner ? 'text-emerald-500' : 'text-accent-red'; - } -} diff --git a/frontend/src/app/feature/game/coinflip/models/coinflip.model.ts b/frontend/src/app/feature/game/coinflip/models/coinflip.model.ts deleted file mode 100644 index f87a3f9..0000000 --- a/frontend/src/app/feature/game/coinflip/models/coinflip.model.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface CoinflipGame { - isWin?: boolean; - win?: boolean; - payout: number; - coinSide: 'HEAD' | 'TAILS'; -} - -export interface CoinflipRequest { - betAmount: number; - coinSide: 'HEAD' | 'TAILS'; -} diff --git a/frontend/src/app/feature/game/dice/dice.component.html b/frontend/src/app/feature/game/dice/dice.component.html deleted file mode 100644 index 6cf5d12..0000000 --- a/frontend/src/app/feature/game/dice/dice.component.html +++ /dev/null @@ -1,305 +0,0 @@ -
-

Dice

-
-
-
-
-
-
-

- Zielwert: - {{ - diceForm.get('targetValue')?.value | number: '1.0-2' - }} -

-
- -
-
- 0 - 25 - 50 - 75 - 100 -
- - - -
-
- - - -
-
- {{ potentialWin() | currency: 'EUR' : 'symbol' : '1.2-2' }} -
- - - {{ diceForm.get('rollOver')?.value ? '>' : '<' }} - -
- - - - @if (rolledValue() !== null) { -
-
-
- } -
- -
- @for (i of [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; track i) { -
- } -
-
- - @if ( - hasError('targetValue', 'required') || - hasError('targetValue', 'min') || - hasError('targetValue', 'max') - ) { -
- @if (hasError('targetValue', 'required')) { - Zielwert ist erforderlich - } - @if (hasError('targetValue', 'min')) { - Zielwert muss mindestens 1 sein - } - @if (hasError('targetValue', 'max')) { - Zielwert darf höchstens 99 sein - } -
- } -
- -
- - -
-
-
- - @if (rolledValue() !== null) { -
-
- @if (win()) { - - - -

- Du hast gewonnen! Auszahlung: {{ payout() | currency: 'EUR' : 'symbol' : '1.2-2' }} -

- } @else { - - - -

Du hast verloren.

- } -
-
- } -
- -
-
-

Spielinformationen

-
-
- Möglicher Gewinn: - {{ - potentialWin() | currency: 'EUR' : 'symbol' : '1.2-2' - }} -
- -
- Gewinnchance: - {{ winChance() | number: '1.0-2' }}% -
- -
- - - - -
- -
-
- -
- - @if (hasError('betAmount', 'required')) { - Einsatz ist erforderlich - } - @if (hasError('betAmount', 'min')) { - Einsatz muss mindestens 0.01 sein - } -
- - - -
-

Spielanleitung

-
    -
  • • Setze deinen Einsatz und Zielwert
  • -
  • • Wähle "Über Zielwert" oder "Unter Zielwert"
  • -
  • • Gewinne, wenn der Würfel zu deinen Gunsten fällt
  • -
  • • Höheres Risiko = höhere Belohnung
  • -
-
-
-
-
-
-
diff --git a/frontend/src/app/feature/game/dice/dice.component.ts b/frontend/src/app/feature/game/dice/dice.component.ts deleted file mode 100644 index aaca5c5..0000000 --- a/frontend/src/app/feature/game/dice/dice.component.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { Component, inject, OnInit, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { - FormBuilder, - FormControl, - FormGroup, - ReactiveFormsModule, - Validators, -} from '@angular/forms'; -import { DiceService } from './dice.service'; -import { DiceDto, DiceResult } from './dice.model'; -import { tap } from 'rxjs/operators'; -import { UserService } from '@service/user.service'; -import { PlaySoundDirective } from '@shared/directives/play-sound.directive'; -import { DragSoundDirective } from '@shared/directives/drag-sound.directive'; -import { AudioService } from '@shared/services/audio.service'; - -type DiceFormGroup = FormGroup<{ - betAmount: FormControl; - rollOver: FormControl; - targetValue: FormControl; -}>; - -@Component({ - selector: 'app-dice', - standalone: true, - imports: [CommonModule, ReactiveFormsModule, PlaySoundDirective, DragSoundDirective], - templateUrl: './dice.component.html', -}) -export default class DiceComponent implements OnInit { - private readonly formBuilder = inject(FormBuilder); - private readonly diceService = inject(DiceService); - private readonly userService = inject(UserService); - private readonly audioService = inject(AudioService); - - rolledValue = signal(null); - win = signal(null); - payout = signal(null); - winChance = signal(0); - potentialWin = signal(0); - - readonly diceForm: DiceFormGroup = this.createDiceForm(); - - private readonly MAX_DICE_VALUE = 100; - - ngOnInit(): void { - this.diceForm.valueChanges - .pipe(tap(() => this.calculateWinChanceAndPotentialWin())) - .subscribe(); - - this.calculateWinChanceAndPotentialWin(); - } - - createDiceForm(): DiceFormGroup { - return this.formBuilder.group({ - betAmount: new FormControl(1, { - validators: [Validators.required, Validators.min(1)], - nonNullable: true, - }), - rollOver: new FormControl(true, { - validators: [Validators.required], - nonNullable: true, - }), - targetValue: new FormControl(50, { - validators: [Validators.required, Validators.min(1), Validators.max(99)], - nonNullable: true, - }), - }); - } - - toggleRollMode(): void { - const currentMode = this.diceForm.get('rollOver')?.value ?? true; - this.diceForm.get('rollOver')?.setValue(!currentMode); - } - - calculateWinChanceAndPotentialWin(): void { - const formValues = this.diceForm.value; - const target = formValues.targetValue ?? 0; - const bet = formValues.betAmount ?? 0; - const isOver = formValues.rollOver ?? true; - - const calculatedWinChance = isOver ? this.MAX_DICE_VALUE - target : target - 1; - - this.winChance.set(Math.max(0, calculatedWinChance)); - - let multiplier = 0; - if (calculatedWinChance > 0) { - multiplier = (this.MAX_DICE_VALUE - 1) / calculatedWinChance; - } - - this.potentialWin.set(bet * multiplier); - } - - roll(): void { - if (this.diceForm.invalid) { - this.diceForm.markAllAsTouched(); - return; - } - - const diceDto: DiceDto = this.diceForm.getRawValue() as DiceDto; - - this.rolledValue.set(null); - this.win.set(null); - this.payout.set(null); - - this.diceService.rollDice(diceDto).subscribe({ - next: (result: DiceResult) => { - this.rolledValue.set(result.rolledValue); - this.win.set(result.win); - this.payout.set(result.payout); - - if (result.win) { - this.audioService.playWinSound(); - } - - this.userService.refreshCurrentUser(); - }, - error: (error) => { - console.error('Dice roll failed:', error); - }, - }); - } - - setBetAmount(percentage: number): void { - const user = this.userService['authService'].currentUserValue; - if (!user) return; - - const balance = user.balance || 0; - - const newBet = Math.max(1, Math.floor(balance * percentage * 100) / 100); - - this.diceForm.get('betAmount')?.setValue(newBet); - this.calculateWinChanceAndPotentialWin(); - } - - getTrackGradient(): string { - const targetValue = this.diceForm.get('targetValue')?.value ?? 50; - const isRollOver = this.diceForm.get('rollOver')?.value ?? true; - - if (isRollOver) { - return `linear-gradient(to right, var(--color-accent-red) ${targetValue}%, var(--color-emerald) ${targetValue}%)`; - } else { - return `linear-gradient(to right, var(--color-accent-red) ${targetValue}%, var(--color-emerald) ${targetValue}%)`; - } - } - - hasError(controlName: string, errorName: string): boolean { - const control = this.diceForm.get(controlName); - return control !== null && control.touched && control.hasError(errorName); - } -} diff --git a/frontend/src/app/feature/game/dice/dice.model.ts b/frontend/src/app/feature/game/dice/dice.model.ts deleted file mode 100644 index 93a1133..0000000 --- a/frontend/src/app/feature/game/dice/dice.model.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface DiceDto { - betAmount: number; - rollOver: boolean; - targetValue: number; -} - -export interface DiceResult { - win: boolean; - payout: number; - rolledValue: number; -} diff --git a/frontend/src/app/feature/game/dice/dice.service.ts b/frontend/src/app/feature/game/dice/dice.service.ts deleted file mode 100644 index a071495..0000000 --- a/frontend/src/app/feature/game/dice/dice.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { DiceDto, DiceResult } from './dice.model'; -import { environment } from '@environments/environment'; - -@Injectable({ - providedIn: 'root', -}) -export class DiceService { - private apiUrl = `${environment.apiUrl}/dice`; - - constructor(private http: HttpClient) {} - - rollDice(diceDto: DiceDto): Observable { - return this.http.post(this.apiUrl, diceDto); - } -} diff --git a/frontend/src/app/feature/game/slots/slots.component.css b/frontend/src/app/feature/game/slots/slots.component.css deleted file mode 100644 index c1fa452..0000000 --- a/frontend/src/app/feature/game/slots/slots.component.css +++ /dev/null @@ -1,16 +0,0 @@ -/* Symbol colors */ -.symbol-BAR { - color: var(--color-accent-yellow); -} -.symbol-SEVEN { - color: var(--color-accent-red); -} -.symbol-BELL { - color: var(--color-accent-purple); -} -.symbol-CHERRY { - color: #ec4899; -} -.symbol-LEMON { - color: #a3e635; -} diff --git a/frontend/src/app/feature/game/slots/slots.component.html b/frontend/src/app/feature/game/slots/slots.component.html deleted file mode 100644 index b7ddcf6..0000000 --- a/frontend/src/app/feature/game/slots/slots.component.html +++ /dev/null @@ -1,173 +0,0 @@ -
-

Spielautomaten

- -
-
-
-
-
-
-

Slot Machine

- - +{{ slotResult().amount | currency: 'EUR' }} - -
- -
- - {{ - slotResult().status === 'win' - ? 'Gewonnen!' - : slotResult().status === 'lose' - ? 'Verloren' - : 'Bereit' - }} - -
-
-
- -
-
-
- @for (row of slotResult().resultMatrix; track $index) { - @for (cell of row; track $index) { -
- {{ - cell - }} -
- } - } -
-
- -
-
- - -
- - -
-
-
-
- -
-
-

Spiel Informationen

-
-
- Kontostand: - - - -
-
- Einsatz: - - - -
- -
- - - - -
- -

Auszahlungen:

- - @if (slotInfo(); as info) { -
    - @for (item of info | keyvalue; track item.key) { -
  • -
    - {{ item.key }} -
    - {{ item.value }}x -
  • - } -
- } @else { -
-
-
- } - -
-

Spielregeln:

-
    -
  • • Gewinne mit 3 gleichen Symbolen
  • -
  • • Höhere Symbole = höhere Gewinne
  • -
-
-
-
-
-
-
diff --git a/frontend/src/app/feature/game/slots/slots.component.ts b/frontend/src/app/feature/game/slots/slots.component.ts deleted file mode 100644 index b297875..0000000 --- a/frontend/src/app/feature/game/slots/slots.component.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - inject, - OnDestroy, - OnInit, - signal, -} from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { CommonModule, CurrencyPipe, KeyValuePipe, NgClass } from '@angular/common'; -import { FormsModule } from '@angular/forms'; -import { UserService } from '@service/user.service'; -import { Subscription } from 'rxjs'; -import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; -import { AuthService } from '@service/auth.service'; - -interface SlotResult { - status: 'win' | 'lose' | 'blank' | 'start'; - amount: number; - resultMatrix: string[][]; -} - -@Component({ - selector: 'app-slots', - standalone: true, - imports: [ - CommonModule, - KeyValuePipe, - NgClass, - FormsModule, - CurrencyPipe, - AnimatedNumberComponent, - ], - templateUrl: './slots.component.html', - styleUrl: './slots.component.css', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export default class SlotsComponent implements OnInit, OnDestroy { - private httpClient: HttpClient = inject(HttpClient); - private userService = inject(UserService); - private authService = inject(AuthService); - private userSubscription: Subscription | undefined; - private winSound: HTMLAudioElement; - - slotInfo = signal | null>(null); - slotResult = signal({ - status: 'start', - amount: 0, - resultMatrix: [ - ['BAR', 'BAR', 'BAR'], - ['SEVEN', 'SEVEN', 'SEVEN'], - ['BELL', 'BELL', 'BELL'], - ], - }); - - balance = signal(0); - betAmount = signal(1); - isSpinning = false; - - constructor() { - this.winSound = new Audio('/sounds/win.mp3'); - } - - ngOnInit(): void { - this.httpClient.get>('/backend/slots/info').subscribe((data) => { - this.slotInfo.set(data); - }); - - this.userSubscription = this.authService.userSubject.subscribe((user) => { - this.balance.set(user?.balance ?? 0); - }); - - this.userService.refreshCurrentUser(); - } - - ngOnDestroy(): void { - if (this.userSubscription) { - this.userSubscription.unsubscribe(); - } - } - - getSymbolClass(symbol: string): string { - return `symbol-${symbol}`; - } - - hasEnoughBalance(): boolean { - return this.balance() >= this.betAmount(); - } - - setBetAmount(percentage: number): void { - const calculatedBet = Math.floor(this.balance() * percentage * 100) / 100; - const minimumBet = 0.01; - - const newBet = Math.max(minimumBet, Math.min(calculatedBet, this.balance())); - - this.betAmount.set(newBet); - } - - spin(): void { - if (!this.hasEnoughBalance()) { - return; - } - - this.isSpinning = true; - const betAmount = this.betAmount(); - - this.userService.updateLocalBalance(-betAmount); - - const payload = { - betAmount: betAmount, - }; - - this.httpClient.post('/backend/slots/spin', payload).subscribe({ - next: (result) => { - setTimeout(() => { - this.slotResult.set(result); - - if (result.status === 'win') { - this.winSound.play(); - this.userService.updateLocalBalance(result.amount); - } - - this.userService.refreshCurrentUser(); - - this.isSpinning = false; - }, 100); - }, - error: (err) => { - console.error('Error spinning slot machine:', err); - this.userService.updateLocalBalance(betAmount); - this.userService.refreshCurrentUser(); - this.isSpinning = false; - }, - }); - } -} diff --git a/frontend/src/app/feature/home/home.component.html b/frontend/src/app/feature/home/home.component.html deleted file mode 100644 index fae788a..0000000 --- a/frontend/src/app/feature/home/home.component.html +++ /dev/null @@ -1,95 +0,0 @@ -
-
-
-
- -
-
-
-

Alle Spiele

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

{{ game.name }}

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

Konto

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

Letzte Transaktionen

-
-
-
-

{{ transaction.status }}

-

- {{ transaction.createdAt | date: 'd.m.Y H:m' }} -

-
- - {{ transaction.amount | currency: 'EUR' }} - -
-
-
-
-
-
diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts deleted file mode 100644 index 1fad4cb..0000000 --- a/frontend/src/app/feature/home/home.component.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; -import { AsyncPipe, CurrencyPipe, DatePipe, NgFor } from '@angular/common'; -import { DepositComponent } from '../deposit/deposit.component'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ConfirmationComponent } from '@shared/components/confirmation/confirmation.component'; -import { Game } from 'app/model/Game'; -import { Observable } from 'rxjs'; -import { TransactionService } from '@service/transaction.service'; -import format from 'ajv/dist/vocabularies/format'; -import { TransactionHistoryComponent } from '../transaction-history/transaction-history.component'; -import { TransactionData } from '../../model/TransactionData'; - -@Component({ - selector: 'app-homepage', - standalone: true, - imports: [ - CurrencyPipe, - NgFor, - DepositComponent, - ConfirmationComponent, - AsyncPipe, - DatePipe, - TransactionHistoryComponent, - ], - templateUrl: './home.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export default class HomeComponent implements OnInit { - isDepositModalOpen = false; - isDepositSuccessful = false; - isTransactionModalOpen = false; - - constructor( - public route: ActivatedRoute, - public router: Router - ) {} - - ngOnInit() { - this.isDepositSuccessful = this.route.snapshot.queryParams['success'] == 'true'; - - this.router.navigate([], { queryParams: {} }); - - if (this.isDepositSuccessful) { - this.openDepositConfirmationModal(); - } - } - - featuredGames: Game[] = [ - { - id: '1', - name: 'Coinflip', - image: '/coinflip.png', - route: '/game/coinflip', - }, - { - id: '2', - name: 'Blackjack', - image: '/blackjack.webp', - route: '/game/blackjack', - }, - { - id: '3', - name: 'Slots', - image: '/slots.webp', - route: '/game/slots', - }, - { - id: '4', - name: 'Plinko', - image: '/plinko.webp', - route: '/game/plinko', - }, - { - id: '5', - name: 'Dice', - image: '/liars-dice.webp', - route: '/game/dice', - }, - { - id: '6', - name: 'Lootboxen', - image: '/lootbox.webp', - route: '/game/lootboxes', - }, - ]; - - allGames: Game[] = [...this.featuredGames]; - - recentTransactionData: Observable = - inject(TransactionService).getUsersTransactions(5); - - openDepositModal() { - this.isDepositModalOpen = true; - } - - closeDepositModal() { - this.isDepositModalOpen = false; - } - - openDepositConfirmationModal() { - this.isDepositSuccessful = true; - } - - openTransactionModal() { - this.isTransactionModalOpen = true; - } - - closeDepositConfirmationModal() { - this.isDepositSuccessful = false; - } - - closeTransactionModal() { - this.isTransactionModalOpen = false; - } - - navigateToGame(route: string) { - this.router.navigate([route]); - } - - protected readonly format = format; -} diff --git a/frontend/src/app/feature/landing/landing.component.html b/frontend/src/app/feature/landing/landing.component.html deleted file mode 100644 index 4cc9c52..0000000 --- a/frontend/src/app/feature/landing/landing.component.html +++ /dev/null @@ -1,218 +0,0 @@ -
-
-
-
-

- Willkommensbonus -

-
von bis zu €100
-

Fangen Sie an, zu gewinnen!

- -
- @if (authService.isLoggedIn()) { - - Spiele - - } @else { - - - } -
-
- -
-

Beliebte Spiele

-
-
-
-
-
-
-

Slots

-

Klassische Spielautomaten

- Jetzt Spielen -
-
-
-
-

Plinko

-

Spannendes Geschicklichkeitsspiel

- Jetzt Spielen -
-
- -
- -
-
-
-

Poker

-

Texas Hold'em & mehr

- Jetzt Spielen -
-
-
-
-

Dice

-

Würfelspiel

- Jetzt Spielen -
-
- -
-
-
- - - - -
- -
-
-
- -
-
-
50 Mio.€+
-
Ausgezahlt
-
- -
-
10 Mio.+
-
Spiele
-
- -
-
24/7
-
Support *
-
-
-
-
- - @if (showLogin() || showRegister() || showRecoverPassword()) { - - - } -
diff --git a/frontend/src/app/feature/landing/landing.component.ts b/frontend/src/app/feature/landing/landing.component.ts deleted file mode 100644 index d354fa4..0000000 --- a/frontend/src/app/feature/landing/landing.component.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - inject, - OnDestroy, - OnInit, - signal, -} from '@angular/core'; -import { NgFor } from '@angular/common'; -import { ActivatedRoute, RouterLink } from '@angular/router'; -import { AuthService } from '@service/auth.service'; -import { LoginComponent } from '../auth/login/login.component'; -import { RegisterComponent } from '../auth/register/register.component'; -import '../auth/recover-password/recover-password.component'; -import RecoverPasswordComponent from '../auth/recover-password/recover-password.component'; - -@Component({ - selector: 'app-landing-page', - standalone: true, - imports: [NgFor, RouterLink, LoginComponent, RegisterComponent, RecoverPasswordComponent], - templateUrl: './landing.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class LandingComponent implements OnInit, OnDestroy { - currentSlide = 0; - private autoplayInterval: ReturnType | undefined; - authService: AuthService = inject(AuthService); - route: ActivatedRoute = inject(ActivatedRoute); - showLogin = signal(false); - showRegister = signal(false); - showRecoverPassword = signal(false); - - ngOnInit() { - this.startAutoplay(); - document.body.style.overflow = 'auto'; - if (this.route.snapshot.queryParamMap.get('login') === 'true') { - this.showLoginForm(); - } - } - - ngOnDestroy() { - this.stopAutoplay(); - document.body.style.overflow = 'auto'; - } - - showLoginForm() { - this.showLogin.set(true); - this.showRegister.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'hidden'; - } - - showRegisterForm() { - this.showRegister.set(true); - this.showLogin.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'hidden'; - } - - showRecoverPasswordForm() { - this.showRecoverPassword.set(true); - this.showLogin.set(false); - this.showRegister.set(false); - document.body.style.overflow = 'hidden'; - } - - hideAuthForms() { - this.showLogin.set(false); - this.showRegister.set(false); - this.showRecoverPassword.set(false); - document.body.style.overflow = 'auto'; - } - - prevSlide() { - this.currentSlide = this.currentSlide === 0 ? 1 : 0; - this.resetAutoplay(); - } - - nextSlide() { - this.currentSlide = this.currentSlide === 1 ? 0 : 1; - this.resetAutoplay(); - } - - goToSlide(index: number) { - this.currentSlide = index; - this.resetAutoplay(); - } - - private startAutoplay() { - this.autoplayInterval = setInterval(() => { - this.nextSlide(); - }, 5000); - } - - private stopAutoplay() { - if (this.autoplayInterval) { - clearInterval(this.autoplayInterval); - } - } - - private resetAutoplay() { - this.stopAutoplay(); - this.startAutoplay(); - } -} diff --git a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.css b/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.css deleted file mode 100644 index 4e5f67f..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.css +++ /dev/null @@ -1,322 +0,0 @@ -body { - background: linear-gradient(to bottom, #181c2a, #232c43); -} - -/* Color classes */ -.text-yellow-400 { - color: #facc15; -} -.text-purple-400 { - color: #a78bfa; -} -.text-blue-400 { - color: #60a5fa; -} - -.border-yellow-400 { - border-color: #facc15; -} -.border-purple-400 { - border-color: #a78bfa; -} -.border-blue-400 { - border-color: #60a5fa; -} - -/* Loader animation */ -.loader { - border: 4px solid rgba(255, 255, 255, 0.3); - border-radius: 50%; - border-top: 4px solid #fff; - width: 40px; - height: 40px; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -/* Open button styling */ -.open-btn { - background: linear-gradient(90deg, #4338ca 0%, #8b5cf6 100%); - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); - transition: all 0.2s ease; -} -.open-btn:hover { - background: linear-gradient(90deg, #4f46e5 0%, #a78bfa 100%); - transform: translateY(-2px); - box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3); -} - -/* CSGO-style case opening display */ -.case-container { - position: relative; - width: 100%; - background: rgba(26, 31, 48, 0.6); - border-radius: 8px; - box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); - overflow: hidden; - margin-bottom: 20px; - display: flex; - justify-content: center; -} - -.case-indicator { - position: absolute; - top: 50%; - left: 50%; /* Back to center - we'll adjust the animation instead */ - transform: translate(-50%, -50%); /* Center precisely */ - width: 6px; - height: 100%; - background: #facc15; - box-shadow: - 0 0 10px #facc15, - 0 0 15px rgba(255, 255, 255, 0.5); - z-index: 3; - animation: indicator-pulse 1.5s ease-in-out 10s infinite alternate; -} - -@keyframes indicator-pulse { - 0% { - opacity: 0.6; - box-shadow: - 0 0 10px #facc15, - 0 0 15px rgba(255, 255, 255, 0.3); - } - 100% { - opacity: 1; - box-shadow: - 0 0 15px #facc15, - 0 0 20px rgba(255, 255, 255, 0.7); - } -} - -.case-items-container { - position: relative; - z-index: 1; - padding: 10px 5px; - margin: 0 auto; - width: 100%; - height: 150px; /* Fixed height for the horizontal row */ - overflow: hidden; /* Hide scrollbar */ - display: flex; - justify-content: center; /* Center the items container */ - align-items: center; -} - -.case-items { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - gap: 8px; - padding: 5px 0; - height: 100%; - width: 100%; - animation: slide-in 10s cubic-bezier(0.33, 0.9, 0.3, 1) forwards; - transform: translateX(4500px); - position: relative; -} - -@keyframes slide-in { - 0% { - transform: translateX(4500px); - } - 100% { - transform: translateX(-37.5px); - } -} - -.case-item { - transition: all 0.2s ease; - padding: 2px; - animation: item-flash 0.3s ease-out forwards; - animation-play-state: paused; - width: 69px; - flex-shrink: 0; -} - -@keyframes item-flash { - 0% { - filter: brightness(1); - } - 50% { - filter: brightness(1.8); - } - 100% { - filter: brightness(1.2); - } -} - -.case-item-inner { - background: #232c43; - border: 2px solid #2d3748; - border-radius: 8px; - padding: 10px 5px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; -} - -.case-item-won { - z-index: 2; - animation: highlight-winner 1s ease-out 10s forwards; -} - -.winning-prize { - border: 2px solid transparent; - transition: all 0.5s ease; -} - -.winning-prize.highlight { - border-color: #fff !important; - box-shadow: 0 0 8px rgba(255, 255, 255, 0.6) !important; -} - -/* Specific ID for the winning item to ensure it's visible */ -#winning-item { - z-index: 5; /* Higher than indicator */ -} - -@keyframes highlight-winner { - 0% { - transform: scale(1); - filter: brightness(1); - } - 10% { - transform: scale(1.1); - filter: brightness(1.5); - } - 20% { - transform: scale(1.05); - filter: brightness(1.3); - } - 30% { - transform: scale(1.1); - filter: brightness(1.5); - } - 40% { - transform: scale(1.05); - filter: brightness(1.3); - } - 50% { - transform: scale(1.1); - filter: brightness(1.5); - } - 60% { - transform: scale(1.05); - filter: brightness(1.3); - } - 70% { - transform: scale(1.1); - filter: brightness(1.5); - } - 80% { - transform: scale(1.05); - filter: brightness(1.3); - } - 90% { - transform: scale(1.1); - filter: brightness(1.5); - } - 100% { - transform: scale(1.05); - filter: brightness(1.3); - } -} - -.amount { - font-size: 1rem; - font-weight: bold; - margin-bottom: 4px; -} - -.rarity { - font-size: 0.75rem; - opacity: 0.7; -} - -/* Prize animation */ -.prize-reel { - animation: slide-prizes 10s cubic-bezier(0.05, 0.82, 0.17, 1) forwards; -} - -@keyframes slide-prizes { - 0% { - transform: translateX(800px); - } - 85% { - transform: translateX(-120px); /* Small overshoot */ - } - 92% { - transform: translateX(-90px); /* Bounce back */ - } - 100% { - transform: translateX(-100px); /* Final position centered */ - } -} - -.animate-item-flash { - animation: item-flash 0.5s ease-out alternate infinite; -} - -.highlight { - animation: highlight-winner 1s ease-out forwards; -} - -/* Reward rarity classes */ -.text-common { - color: #ffffff; -} - -.text-uncommon { - color: #4ade80; -} - -.text-rare { - color: #60a5fa; -} - -.text-epic { - color: #a78bfa; -} - -.text-legendary { - color: #facc15; -} - -.text-mythic { - color: #f87171; -} - -.text-emerald { - color: #10b981; -} - -.text-accent-red { - color: #ef4444; -} - -.animation-fade { - opacity: 0; - transform: translateY(10px); - transition: - opacity 0.5s ease-out, - transform 0.5s ease-out; - transition-delay: 0.5s; - pointer-events: none; /* Prevent clicks when invisible */ -} - -.animation-fade.visible { - opacity: 1; - transform: translateY(0); - pointer-events: auto; /* Enable clicks when visible */ -} diff --git a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.html b/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.html deleted file mode 100644 index d4abab7..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.html +++ /dev/null @@ -1,166 +0,0 @@ -
-

Lootbox Öffnen

- -
-
-
- -
- {{ error }} -
- -
-
-
-
- -
- {{ lootbox.price | currency: 'EUR' }} -
-
- -
-

{{ lootbox.name }}

- -
- -
- -
-
-
Öffne Lootbox...
-
- -
-
-

Dein Gewinn:

-
- {{ wonReward?.value | currency: 'EUR' }} -
-
- -
-
- -
-
-
-
-
- {{ reward.value | currency: 'EUR' }} -
-
- {{ reward.probability * 100 | number: '1.0-0' }}% -
-
-
-
-
-
- -
- - -
-
-
- -
-
-

Fairness garantiert - Alle Ergebnisse werden transparent berechnet.

-
-
-
-
- -
-
-

Mögliche Gewinne:

-
    -
  • - {{ - reward.value | currency: 'EUR' - }} - {{ reward.probability * 100 | number: '1.0-0' }}% -
  • -
- -
-

Gewinn-Details:

-
-
- Kosten: - {{ lootbox.price | currency: 'EUR' }} -
-
- Gewinn: - {{ wonReward.value | currency: 'EUR' }} -
-
- Profit: - - {{ wonReward.value - (lootbox.price || 0) | currency: 'EUR' }} - -
-
-
-
-
-
-
diff --git a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.ts b/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.ts deleted file mode 100644 index 3faf5be..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-opening/lootbox-opening.component.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { ChangeDetectorRef, Component } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ActivatedRoute, Router } from '@angular/router'; -import { LootboxService } from '../services/lootbox.service'; -import { LootBox, Reward } from 'app/model/LootBox'; -import { UserService } from '@service/user.service'; -import { User } from 'app/model/User'; -import { AuthService } from '@service/auth.service'; - -@Component({ - selector: 'app-lootbox-opening', - standalone: true, - imports: [CommonModule], - templateUrl: './lootbox-opening.component.html', - styleUrls: ['./lootbox-opening.component.css'], -}) -export default class LootboxOpeningComponent { - lootbox: LootBox | null = null; - isLoading = true; - error = ''; - isOpening = false; - isOpen = false; - wonReward: Reward | null = null; - prizeList: Reward[] = []; - animationCompleted = false; - currentUser: User | null = null; - private winSound: HTMLAudioElement; - - constructor( - private route: ActivatedRoute, - private router: Router, - private lootboxService: LootboxService, - private userService: UserService, - private authService: AuthService, - private cdr: ChangeDetectorRef - ) { - this.winSound = new Audio('/sounds/win.mp3'); - this.loadLootbox(); - this.authService.userSubject.subscribe((user) => { - this.currentUser = user; - this.cdr.detectChanges(); - }); - } - - private loadLootbox(): void { - const idParam = this.route.snapshot.paramMap.get('id'); - if (!idParam) { - this.error = 'Invalid lootbox ID'; - this.isLoading = false; - return; - } - - const lootboxId = parseInt(idParam, 10); - this.lootboxService.getAllLootBoxes().subscribe({ - next: (lootboxes) => { - this.lootbox = lootboxes.find((box) => box.id === lootboxId) || null; - this.isLoading = false; - this.cdr.detectChanges(); - }, - error: () => { - this.error = 'Failed to load lootbox data'; - this.isLoading = false; - this.cdr.detectChanges(); - }, - }); - } - - openLootbox(): void { - if (!this.lootbox || this.isOpening) return; - - // Check if user has enough balance - if (!this.hasEnoughBalance()) { - this.error = 'Nicht genug Guthaben, um diese Lootbox zu öffnen.'; - window.scrollTo(0, 0); - this.cdr.detectChanges(); - setTimeout(() => { - this.error = ''; - this.cdr.detectChanges(); - }, 5000); - return; - } - - this.resetState(true); - - if (this.lootbox.price) { - this.userService.updateLocalBalance(-this.lootbox.price); - } - - setTimeout(() => { - this.lootboxService.purchaseLootBox(this.lootbox!.id).subscribe({ - next: this.handleRewardSuccess.bind(this), - error: this.handleRewardError.bind(this), - }); - }, 100); - } - - private handleRewardSuccess(reward: Reward): void { - this.wonReward = reward; - this.generateCasePrizes(reward); - this.isOpening = false; - this.isOpen = true; - - this.cdr.detectChanges(); - } - - private handleRewardError(): void { - if (!this.lootbox) return; - - const rewards = this.lootbox.rewards; - const fallback = rewards[Math.floor(Math.random() * rewards.length)]; - - this.wonReward = fallback; - this.generateCasePrizes(fallback); - this.isOpening = false; - this.isOpen = true; - this.cdr.detectChanges(); - } - - private resetState(isOpening = false): void { - this.isOpening = isOpening; - this.isOpen = false; - this.wonReward = null; - this.prizeList = []; - this.animationCompleted = false; - this.cdr.detectChanges(); - } - - generateCasePrizes(wonReward: Reward): void { - if (!this.lootbox) return; - - const prizeCount = 120; - const winningPosition = Math.floor(prizeCount / 2); - const possibleRewards = this.lootbox.rewards; - const items: Reward[] = []; - - for (let i = 0; i < prizeCount; i++) { - if (i === winningPosition) { - items.push({ ...wonReward }); - } else { - items.push(this.getWeightedRandomReward(possibleRewards)); - } - } - - this.prizeList = items; - - setTimeout(() => { - this.animationCompleted = true; - - if (this.wonReward) { - this.winSound.play(); - this.userService.updateLocalBalance(this.wonReward.value); - } - - this.userService.refreshCurrentUser(); - this.cdr.detectChanges(); - }, 10000); - } - - getWeightedRandomReward(rewards: Reward[]): Reward { - const totalProbability = rewards.reduce((sum, reward) => sum + reward.probability, 0); - const randomValue = Math.random() * totalProbability; - let cumulativeProbability = 0; - - for (const reward of rewards) { - cumulativeProbability += reward.probability; - if (randomValue <= cumulativeProbability) { - return { ...reward }; - } - } - - return { ...rewards[0] }; - } - - openAgain(): void { - this.resetState(); - this.openLootbox(); - } - - getBoxImage(id: number): string { - return `/images/${id}-box.png`; - } - - goBack(): void { - this.router.navigate(['/game/lootboxes']); - } - - isWonReward(reward: Reward): boolean { - if (!this.wonReward || !this.prizeList.length) return false; - - const middleIndex = Math.floor(this.prizeList.length / 2); - return this.prizeList.indexOf(reward) === middleIndex; - } - - getRewardRarityClass(reward: Reward): string { - if (!reward) return 'text-common'; - - const probability = reward.probability; - - if (probability < 0.01) return 'text-mythic'; - if (probability < 0.05) return 'text-legendary'; - if (probability < 0.1) return 'text-epic'; - if (probability < 0.2) return 'text-rare'; - if (probability < 0.4) return 'text-uncommon'; - return 'text-common'; - } - - getRewardClass(): string { - if (!this.wonReward || !this.lootbox) return ''; - return this.wonReward.value > (this.lootbox.price || 0) ? 'text-emerald' : 'text-accent-red'; - } - - hasEnoughBalance(): boolean { - if (!this.currentUser || !this.lootbox) return false; - return this.currentUser.balance >= this.lootbox.price; - } -} diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.css b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.css deleted file mode 100644 index 878220b..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.css +++ /dev/null @@ -1,28 +0,0 @@ -.loader { - border: 4px solid rgba(255, 255, 255, 0.3); - border-radius: 50%; - border-top: 4px solid #fff; - width: 40px; - height: 40px; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -.card { - transition: - transform 0.3s ease, - box-shadow 0.3s ease; -} - -.card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); -} diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html deleted file mode 100644 index 76fcc04..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html +++ /dev/null @@ -1,66 +0,0 @@ -
-

Lootboxen

- -
-
-
- -
- {{ error }} -
- -
-
-
- -
- {{ lootbox.price | currency: 'EUR' }} -
-
- -
-

{{ lootbox.name }}

- -
-

Mögliche Gewinne:

-
    -
  • - {{ - reward.value | currency: 'EUR' - }} - {{ formatProbability(reward.probability) }} -
  • -
-
- -
- -
-
- -
-
-

Fairness garantiert - Alle Ergebnisse werden transparent berechnet.

-
-
-
-
-
diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts deleted file mode 100644 index 373199b..0000000 --- a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { LootboxService } from '../services/lootbox.service'; -import { LootBox } from 'app/model/LootBox'; -import { Router } from '@angular/router'; -import { timeout } from 'rxjs'; -import { User } from 'app/model/User'; -import { AuthService } from '@service/auth.service'; -import { UserService } from '@service/user.service'; - -@Component({ - selector: 'app-lootbox-selection', - standalone: true, - imports: [CommonModule], - templateUrl: './lootbox-selection.component.html', - styleUrls: ['./lootbox-selection.component.css'], -}) -export default class LootboxSelectionComponent implements OnInit { - lootboxes: LootBox[] = []; - isLoading = true; - error = ''; - currentUser: User | null = null; - - // Fallback data in case the API call fails - fallbackLootboxes: LootBox[] = [ - { - id: 1, - name: 'Basic LootBox', - price: 2.0, - rewards: [ - { - id: 1, - value: 0.5, - probability: 0.7, - }, - { - id: 5, - value: 5.0, - probability: 0.3, - }, - ], - }, - { - id: 2, - name: 'Premium LootBox', - price: 5.0, - rewards: [ - { - id: 4, - value: 2.0, - probability: 0.6, - }, - { - id: 5, - value: 5.0, - probability: 0.3, - }, - { - id: 6, - value: 15.0, - probability: 0.1, - }, - ], - }, - { - id: 3, - name: 'Legendäre LootBox', - price: 15.0, - rewards: [ - { - id: 4, - value: 2.0, - probability: 0.6, - }, - { - id: 5, - value: 5.0, - probability: 0.3, - }, - { - id: 6, - value: 15.0, - probability: 0.1, - }, - ], - }, - ]; - - constructor( - private lootboxService: LootboxService, - private router: Router, - private cdr: ChangeDetectorRef, - private authService: AuthService, - private userService: UserService - ) {} - - ngOnInit(): void { - this.loadLootboxes(); - this.authService.userSubject.subscribe((user) => { - this.currentUser = user; - this.cdr.detectChanges(); - }); - } - - loadLootboxes(): void { - this.isLoading = true; - this.lootboxService - .getAllLootBoxes() - .pipe(timeout(5000)) - .subscribe({ - next: (data) => { - console.log('Received lootboxes:', data); - this.lootboxes = data; - this.isLoading = false; - this.cdr.detectChanges(); - }, - error: (err) => { - this.error = 'Konnte keine Verbindung zum Backend herstellen. Zeige Demo-Daten.'; - this.lootboxes = this.fallbackLootboxes; - this.isLoading = false; - this.cdr.detectChanges(); - console.error('Failed to load lootboxes:', err); - }, - }); - } - - getBoxImage(id: number): string { - return `/images/${id}-box.png`; - } - - openLootbox(lootboxId: number): void { - const lootbox = this.lootboxes.find((box) => box.id === lootboxId); - - if (!lootbox) { - return; - } - - if (!this.currentUser || this.currentUser.balance < lootbox.price) { - this.error = 'Nicht genug Guthaben, um diese Lootbox zu öffnen.'; - // Scroll to top to see the error message - window.scrollTo(0, 0); - this.cdr.detectChanges(); - setTimeout(() => { - this.error = ''; - this.cdr.detectChanges(); - }, 5000); - return; - } - - this.router.navigate(['/game/lootboxes/open', lootboxId]); - } - - getRarityClass(probability: number): string { - if (probability <= 0.1) { - return 'text-yellow-400'; // Legendary - } else if (probability <= 0.3) { - return 'text-purple-400'; // Rare - } else { - return 'text-blue-400'; // Common - } - } - - formatProbability(probability: number): string { - return (probability * 100).toFixed(0) + '%'; - } - - hasEnoughBalance(price: number): boolean { - return !!this.currentUser && this.currentUser.balance >= price; - } -} diff --git a/frontend/src/app/feature/lootboxes/services/lootbox.service.ts b/frontend/src/app/feature/lootboxes/services/lootbox.service.ts deleted file mode 100644 index 1d1661a..0000000 --- a/frontend/src/app/feature/lootboxes/services/lootbox.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { catchError, Observable } from 'rxjs'; -import { LootBox, Reward } from 'app/model/LootBox'; - -@Injectable({ - providedIn: 'root', -}) -export class LootboxService { - private http = inject(HttpClient); - - getAllLootBoxes(): Observable { - return this.http.get('/backend/lootboxes', { responseType: 'json' }).pipe( - catchError((error) => { - console.error('Get lootboxes error:', error); - throw error; - }) - ); - } - - purchaseLootBox(lootBoxId: number): Observable { - return this.http - .post(`/backend/lootboxes/${lootBoxId}`, {}, { responseType: 'json' }) - .pipe( - catchError((error) => { - console.error('Purchase lootbox error:', error); - throw error; - }) - ); - } -} diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.css b/frontend/src/app/feature/transaction-history/transaction-history.component.css deleted file mode 100644 index c68e294..0000000 --- a/frontend/src/app/feature/transaction-history/transaction-history.component.css +++ /dev/null @@ -1,8 +0,0 @@ -button[disabled] { - cursor: not-allowed; - background-color: #077b58; - box-shadow: none; -} -button[disabled]:hover { - background-color: #077b58; -} diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.html b/frontend/src/app/feature/transaction-history/transaction-history.component.html deleted file mode 100644 index 974964c..0000000 --- a/frontend/src/app/feature/transaction-history/transaction-history.component.html +++ /dev/null @@ -1,60 +0,0 @@ - diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.ts b/frontend/src/app/feature/transaction-history/transaction-history.component.ts deleted file mode 100644 index 338ef4e..0000000 --- a/frontend/src/app/feature/transaction-history/transaction-history.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - inject, - Input, - Output, -} from '@angular/core'; -import { TransactionService } from '@service/transaction.service'; -import { Observable } from 'rxjs'; -import { AsyncPipe, CurrencyPipe, DatePipe, NgIf } from '@angular/common'; -import { TransactionData } from '../../model/TransactionData'; - -const PER_PAGE = 5; - -@Component({ - standalone: true, - selector: 'app-transaction-history', - imports: [AsyncPipe, CurrencyPipe, DatePipe, NgIf], - templateUrl: './transaction-history.component.html', - styleUrl: './transaction-history.component.css', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class TransactionHistoryComponent { - @Input() - isOpen = false; - @Output() - closeEventEmitter = new EventEmitter(); - - protected offset = 0; - - private transactionService: TransactionService = inject(TransactionService); - transactionData$: Observable = this.loadTransactions(); - - closeDialog() { - this.isOpen = false; - this.closeEventEmitter.emit(); - } - - forward() { - this.offset++; - this.transactionData$ = this.loadTransactions(); - } - - back() { - this.offset--; - this.transactionData$ = this.loadTransactions(); - } - - loadTransactions() { - return this.transactionService.getUsersTransactions(PER_PAGE, this.offset * PER_PAGE); - } -} diff --git a/frontend/src/app/model/Game.ts b/frontend/src/app/model/Game.ts deleted file mode 100644 index 9adbf7a..0000000 --- a/frontend/src/app/model/Game.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Game { - id: string; - name: string; - image: string; - route: string; -} diff --git a/frontend/src/app/model/LootBox.ts b/frontend/src/app/model/LootBox.ts deleted file mode 100644 index ebcf6e8..0000000 --- a/frontend/src/app/model/LootBox.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface Reward { - id: number; - value: number; - probability: number; -} - -export interface LootBox { - id: number; - name: string; - price: number; - rewards: Reward[]; -} diff --git a/frontend/src/app/model/Transaction.ts b/frontend/src/app/model/Transaction.ts deleted file mode 100644 index d3bccf1..0000000 --- a/frontend/src/app/model/Transaction.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Transaction { - status: string; - amount: number; - createdAt: string; -} diff --git a/frontend/src/app/model/TransactionData.ts b/frontend/src/app/model/TransactionData.ts deleted file mode 100644 index 2da39bb..0000000 --- a/frontend/src/app/model/TransactionData.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Transaction } from './Transaction'; - -export interface TransactionData { - transactions: Transaction[]; - hasMore: boolean; -} diff --git a/frontend/src/app/model/User.ts b/frontend/src/app/model/User.ts deleted file mode 100644 index 3c983b8..0000000 --- a/frontend/src/app/model/User.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface User { - id: number; - email: string; - username: string; - balance: number; -} diff --git a/frontend/src/app/model/auth/AuthResponse.ts b/frontend/src/app/model/auth/AuthResponse.ts deleted file mode 100644 index 495d0cd..0000000 --- a/frontend/src/app/model/auth/AuthResponse.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface AuthResponse { - token: string; - tokenType: string; -} diff --git a/frontend/src/app/model/auth/LoginRequest.ts b/frontend/src/app/model/auth/LoginRequest.ts deleted file mode 100644 index 98c1b0e..0000000 --- a/frontend/src/app/model/auth/LoginRequest.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface LoginRequest { - usernameOrEmail: string; - password: string; -} diff --git a/frontend/src/app/model/auth/RegisterRequest.ts b/frontend/src/app/model/auth/RegisterRequest.ts deleted file mode 100644 index 2b07d41..0000000 --- a/frontend/src/app/model/auth/RegisterRequest.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface RegisterRequest { - email: string; - username: string; - password: string; -} diff --git a/frontend/src/app/service/auth.service.ts b/frontend/src/app/service/auth.service.ts deleted file mode 100644 index 61b3e7d..0000000 --- a/frontend/src/app/service/auth.service.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { BehaviorSubject, Observable, tap } from 'rxjs'; -import { Router, ActivatedRoute } from '@angular/router'; -import { LoginRequest } from '../model/auth/LoginRequest'; -import { RegisterRequest } from '../model/auth/RegisterRequest'; -import { AuthResponse } from '../model/auth/AuthResponse'; -import { User } from '../model/User'; -import { environment } from '@environments/environment'; - -const TOKEN_KEY = 'token'; -const USER_KEY = 'user'; - -@Injectable({ - providedIn: 'root', -}) -export class AuthService { - private authUrl = `${environment.apiUrl}/auth`; - private userUrl = `${environment.apiUrl}/users`; - private oauthUrl = `${environment.apiUrl}/oauth2`; - - userSubject: BehaviorSubject; - - constructor( - private http: HttpClient, - private router: Router, - private route: ActivatedRoute - ) { - this.userSubject = new BehaviorSubject(this.getUserFromStorage()); - - // Check for token in URL (OAuth callback) on initialization - this.route.queryParams.subscribe((params) => { - const token = params['token']; - if (token) { - this.handleOAuthCallback(token); - } - }); - - if (this.getToken()) { - this.loadCurrentUser(); - } - } - - private handleOAuthCallback(token: string): void { - this.setToken(token); - this.loadCurrentUser(); - // Clean up the URL by removing the token - this.router.navigate([], { - relativeTo: this.route, - queryParams: {}, - replaceUrl: true, - }); - } - - public get currentUserValue(): User | null { - return this.userSubject.value; - } - - login(loginRequest: LoginRequest): Observable { - return this.http.post(`${this.authUrl}/login`, loginRequest).pipe( - tap((response) => { - this.setToken(response.token); - this.loadCurrentUser(); - }) - ); - } - - register(registerRequest: RegisterRequest): Observable { - return this.http.post(`${this.authUrl}/register`, registerRequest); - } - - githubAuth(code: string): Observable { - return this.http.post(`${this.oauthUrl}/github/callback`, { code }).pipe( - tap((response) => { - console.log(response.token); - this.setToken(response.token); - this.loadCurrentUser(); - }) - ); - } - - googleAuth(code: string): Observable { - return this.http.post(`${this.oauthUrl}/google/callback`, { code }).pipe( - tap((response) => { - this.setToken(response.token); - this.loadCurrentUser(); - }) - ); - } - - logout(): void { - localStorage.removeItem(TOKEN_KEY); - localStorage.removeItem(USER_KEY); - this.userSubject.next(null); - this.router.navigate(['/']); - } - - isLoggedIn(): boolean { - return !!this.getToken(); - } - - getToken(): string | null { - return localStorage.getItem(TOKEN_KEY); - } - - public loadCurrentUser(): void { - this.http.get(`${this.userUrl}/me`).subscribe({ - next: (user) => { - this.setUser(user); - }, - error: () => { - this.logout(); - }, - }); - } - - public verifyEmail(token: string): Observable { - return this.http.post(`${this.authUrl}/verify?token=${token}`, null); - } - - public recoverPassword(email: string): Observable { - return this.http.post(`${this.authUrl}/recover-password?email=${email}`, null); - } - - public resetPassword(token: string, password: string): Observable { - return this.http.post(`${this.authUrl}/reset-password`, { token, password }); - } - - private setToken(token: string): void { - localStorage.setItem(TOKEN_KEY, token); - } - - private setUser(user: User): void { - localStorage.setItem(USER_KEY, JSON.stringify(user)); - this.userSubject.next(user); - } - - private getUserFromStorage(): User | null { - const user = localStorage.getItem(USER_KEY); - return user ? JSON.parse(user) : null; - } - - getUser(): User | null { - return this.currentUserValue; - } -} diff --git a/frontend/src/app/service/deposit.service.ts b/frontend/src/app/service/deposit.service.ts deleted file mode 100644 index 02c8ea1..0000000 --- a/frontend/src/app/service/deposit.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -@Injectable({ - providedIn: 'root', -}) -export class DepositService { - private http: HttpClient = inject(HttpClient); - - handleDeposit(amount: number): Observable<{ sessionId: string }> { - return this.http.post<{ sessionId: string }>('/backend/deposit/checkout', { amount }); - } -} diff --git a/frontend/src/app/service/transaction.service.ts b/frontend/src/app/service/transaction.service.ts deleted file mode 100644 index 55aba0f..0000000 --- a/frontend/src/app/service/transaction.service.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { TransactionData } from '../model/TransactionData'; - -@Injectable({ - providedIn: 'root', -}) -export class TransactionService { - private http: HttpClient = inject(HttpClient); - - public getUsersTransactions(limit: number | null = null, offset: number | null = null) { - const baseUrl = new URL(`${window.location.origin}/backend/user/transactions`); - - if (limit !== null) { - baseUrl.searchParams.append('limit', limit.toString()); - } - - if (offset !== null) { - baseUrl.searchParams.append('offset', offset.toString()); - } - - return this.http.get(`${baseUrl}`); - } -} diff --git a/frontend/src/app/service/user.service.ts b/frontend/src/app/service/user.service.ts deleted file mode 100644 index e126fc4..0000000 --- a/frontend/src/app/service/user.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { AuthService } from '@service/auth.service'; -import { User } from '../model/User'; - -@Injectable({ - providedIn: 'root', -}) -export class UserService { - private authService = inject(AuthService); - - /** - * Updates the user's balance locally for immediate UI feedback - * This should be called before a server-side balance change is made - * The server update will be reflected when AuthService.loadCurrentUser() is called - */ - public updateLocalBalance(amount: number): void { - const currentUser = this.authService.currentUserValue; - if (currentUser) { - const updatedUser: User = { - ...currentUser, - balance: currentUser.balance + amount, - }; - this.authService.userSubject.next(updatedUser); - } - } - - /** - * Refreshes the current user's data from the server - */ - public refreshCurrentUser(): void { - this.authService.loadCurrentUser(); - } -} diff --git a/frontend/src/app/shared/components/confirmation/confirmation.component.html b/frontend/src/app/shared/components/confirmation/confirmation.component.html deleted file mode 100644 index 193ea9a..0000000 --- a/frontend/src/app/shared/components/confirmation/confirmation.component.html +++ /dev/null @@ -1,11 +0,0 @@ -@if (successful) { - -} diff --git a/frontend/src/app/shared/components/confirmation/confirmation.component.ts b/frontend/src/app/shared/components/confirmation/confirmation.component.ts deleted file mode 100644 index 9ce91ba..0000000 --- a/frontend/src/app/shared/components/confirmation/confirmation.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - AfterViewInit, - Component, - ElementRef, - EventEmitter, - Input, - OnDestroy, - Output, - ViewChild, -} from '@angular/core'; -import { ModalAnimationService } from '@shared/services/modal-animation.service'; -import gsap from 'gsap'; - -@Component({ - selector: 'app-confirmation', - standalone: true, - imports: [], - templateUrl: './confirmation.component.html', -}) -export class ConfirmationComponent implements AfterViewInit, OnDestroy { - @Input() successful = true; - @Output() closeConfirmation = new EventEmitter(); - @ViewChild('modalBg') modalBg!: ElementRef; - @ViewChild('modalCard') modalCard!: ElementRef; - - constructor(private modalAnimationService: ModalAnimationService) {} - - ngAfterViewInit() { - if (this.successful) { - this.openModal(); - } - } - - ngOnDestroy() { - gsap.killTweensOf([this.modalBg?.nativeElement, this.modalCard?.nativeElement]); - } - - private openModal() { - this.modalAnimationService.openModal(this.modalCard.nativeElement, this.modalBg.nativeElement); - } - - public closeModal() { - this.modalAnimationService.closeModal( - this.modalCard.nativeElement, - this.modalBg.nativeElement, - () => this.closeConfirmation.emit() - ); - } -} diff --git a/frontend/src/app/shared/components/debt-dialog/debt-dialog.component.ts b/frontend/src/app/shared/components/debt-dialog/debt-dialog.component.ts deleted file mode 100644 index a97f431..0000000 --- a/frontend/src/app/shared/components/debt-dialog/debt-dialog.component.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output, - signal, -} from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { animate, style, transition, trigger } from '@angular/animations'; -import { interval, Subscription, takeWhile } from 'rxjs'; -import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; - -@Component({ - selector: 'app-debt-dialog', - standalone: true, - imports: [CommonModule, AnimatedNumberComponent], - template: ` - - `, - changeDetection: ChangeDetectionStrategy.OnPush, - animations: [ - trigger('fadeInOut', [ - transition(':enter', [ - style({ opacity: 0 }), - animate('150ms ease-out', style({ opacity: 1 })), - ]), - transition(':leave', [animate('150ms ease-in', style({ opacity: 0 }))]), - ]), - trigger('cardAnimation', [ - transition(':enter', [ - style({ opacity: 0, transform: 'scale(0.95)' }), - animate('200ms ease-out', style({ opacity: 1, transform: 'scale(1)' })), - ]), - ]), - trigger('countdown', [ - transition('* => *', [ - style({ transform: 'scale(1.2)' }), - animate('100ms ease-out', style({ transform: 'scale(1)' })), - ]), - ]), - ], -}) -export class DebtDialogComponent implements OnInit, OnDestroy { - @Input() amount = 0; - @Input() set show(value: boolean) { - this.visible = value; - if (value) { - this.startTimer(); - } - } - - @Output() dialogClosed = new EventEmitter(); - - visible = false; - timeLeft = signal(30); - private timerSubscription: Subscription | undefined; - private warningSound = new Audio('assets/sounds/warning.mp3'); - - ngOnInit() { - if (this.visible) { - this.startTimer(); - } - } - - ngOnDestroy() { - this.stopTimer(); - } - - private startTimer() { - this.timeLeft.set(30); - this.timerSubscription = interval(1000) - .pipe(takeWhile(() => this.timeLeft() > 0)) - .subscribe(() => { - this.timeLeft.update((value) => value - 1); - if (this.timeLeft() <= 5) { - this.warningSound.play(); - } - if (this.timeLeft() === 0) { - setTimeout(() => this.closeDialog(), 5000); - } - }); - } - - private stopTimer() { - if (this.timerSubscription) { - this.timerSubscription.unsubscribe(); - } - } - - closeDialog(): void { - this.stopTimer(); - this.visible = false; - this.dialogClosed.emit(); - } -} diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html deleted file mode 100644 index e886973..0000000 --- a/frontend/src/app/shared/components/footer/footer.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
-
- - - -
- -
- - - - - - - -
-
-
- -
-
- -
-
-
-
diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts deleted file mode 100644 index 2cb56e1..0000000 --- a/frontend/src/app/shared/components/footer/footer.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { faCreditCard, faMoneyBillTransfer, faWallet } from '@fortawesome/free-solid-svg-icons'; -import { faApplePay, faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; - -@Component({ - selector: 'app-footer', - standalone: true, - templateUrl: './footer.component.html', - imports: [FontAwesomeModule], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class FooterComponent { - currentYear: number = new Date().getFullYear(); - - faPaypal = faPaypal; - faCreditCard = faCreditCard; - faMoneyBillTransfer = faMoneyBillTransfer; - faWallet = faWallet; - faGooglePay = faGooglePay; - faApplePay = faApplePay; -} diff --git a/frontend/src/app/shared/components/navbar/navbar.component.html b/frontend/src/app/shared/components/navbar/navbar.component.html deleted file mode 100644 index 7e010fa..0000000 --- a/frontend/src/app/shared/components/navbar/navbar.component.html +++ /dev/null @@ -1,95 +0,0 @@ - diff --git a/frontend/src/app/shared/components/navbar/navbar.component.ts b/frontend/src/app/shared/components/navbar/navbar.component.ts deleted file mode 100644 index 7b8bb63..0000000 --- a/frontend/src/app/shared/components/navbar/navbar.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - inject, - OnDestroy, - OnInit, - Output, - signal, -} from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { AuthService } from '@service/auth.service'; -import { Subscription } from 'rxjs'; -import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; - -@Component({ - selector: 'app-navbar', - templateUrl: './navbar.component.html', - standalone: true, - imports: [RouterModule, AnimatedNumberComponent], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class NavbarComponent implements OnInit, OnDestroy { - isMenuOpen = false; - private authService: AuthService = inject(AuthService); - isLoggedIn = signal(this.authService.isLoggedIn()); - - private authSubscription!: Subscription; - public balance = signal(0); - - @Output() showLogin = new EventEmitter(); - @Output() showRegister = new EventEmitter(); - - ngOnInit() { - this.authSubscription = this.authService.userSubject.subscribe({ - next: (user) => { - this.balance.set(user?.balance ?? 0); - this.isLoggedIn.set(this.authService.isLoggedIn()); - }, - }); - } - - ngOnDestroy() { - this.authSubscription.unsubscribe(); - } - - logout() { - this.authService.logout(); - } - - toggleMenu() { - this.isMenuOpen = !this.isMenuOpen; - } -} diff --git a/frontend/src/app/shared/directives/drag-sound.directive.ts b/frontend/src/app/shared/directives/drag-sound.directive.ts deleted file mode 100644 index 332cacc..0000000 --- a/frontend/src/app/shared/directives/drag-sound.directive.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Directive, ElementRef, HostListener, inject, Input, OnInit } from '@angular/core'; -import { AudioService } from '../services/audio.service'; -import { AbstractControl } from '@angular/forms'; - -@Directive({ - selector: '[appDragSound]', - standalone: true, -}) -export class DragSoundDirective implements OnInit { - private audioService = inject(AudioService); - private elementRef = inject(ElementRef); - private lastValue: number | null = null; - - @Input('appDragSound') formControl: AbstractControl | null = null; - - ngOnInit() { - if (this.formControl) { - this.lastValue = this.formControl.value; - - this.formControl.valueChanges.subscribe((newValue) => { - if (this.lastValue !== newValue) { - this.playSound(); - this.lastValue = newValue; - } - }); - } - } - - private playSound() { - this.audioService.playDragStepSound(); - } - - @HostListener('input') - onInput() { - if (!this.formControl) { - this.playSound(); - } - } -} diff --git a/frontend/src/app/shared/directives/play-sound.directive.ts b/frontend/src/app/shared/directives/play-sound.directive.ts deleted file mode 100644 index f949f64..0000000 --- a/frontend/src/app/shared/directives/play-sound.directive.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Directive, HostListener, inject } from '@angular/core'; -import { AudioService } from '../services/audio.service'; - -@Directive({ - selector: '[appPlaySound]', - standalone: true, -}) -export class PlaySoundDirective { - private audioService = inject(AudioService); - - @HostListener('click') - onClick() { - this.audioService.playBetSound(); - } -} diff --git a/frontend/src/app/shared/interceptor/http.interceptor.ts b/frontend/src/app/shared/interceptor/http.interceptor.ts deleted file mode 100644 index 2ff7788..0000000 --- a/frontend/src/app/shared/interceptor/http.interceptor.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { HttpInterceptorFn } from '@angular/common/http'; - -const TOKEN_KEY = 'token'; - -export const httpInterceptor: HttpInterceptorFn = (req, next) => { - const token = localStorage.getItem(TOKEN_KEY); - - // Always add CORS headers - if (token) { - return next( - req.clone({ - setHeaders: { - Authorization: `Bearer ${token}`, - 'Referrer-Policy': 'no-referrer', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': '*', - }, - }) - ); - } else { - return next( - req.clone({ - setHeaders: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': '*', - }, - }) - ); - } -}; diff --git a/frontend/src/app/shared/services/audio.service.ts b/frontend/src/app/shared/services/audio.service.ts deleted file mode 100644 index 53850c0..0000000 --- a/frontend/src/app/shared/services/audio.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root', -}) -export class AudioService { - private audioCache = new Map(); - - private getAudio(soundName: string): HTMLAudioElement { - if (this.audioCache.has(soundName)) { - return this.audioCache.get(soundName)!; - } - - const audio = new Audio(`/sounds/${soundName}`); - this.audioCache.set(soundName, audio); - return audio; - } - - playBetSound(): void { - const audio = this.getAudio('bet.mp3'); - audio.currentTime = 0; - audio.play().catch((error) => console.error('Error playing bet sound:', error)); - } - - playWinSound(): void { - const audio = this.getAudio('win.mp3'); - audio.currentTime = 0; - audio.play().catch((error) => console.error('Error playing win sound:', error)); - } - - getDragSound(): HTMLAudioElement { - return this.getAudio('drag.mp3'); - } - - playDragStepSound(): void { - const audio = this.getAudio('drag.mp3'); - audio.currentTime = 0; - audio.volume = 0.5; - audio.play().catch((error) => console.error('Error playing drag step sound:', error)); - } -} diff --git a/frontend/src/app/shared/services/modal-animation.service.ts b/frontend/src/app/shared/services/modal-animation.service.ts deleted file mode 100644 index f54c2bc..0000000 --- a/frontend/src/app/shared/services/modal-animation.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@angular/core'; -import gsap from 'gsap'; - -@Injectable({ - providedIn: 'root', -}) -export class ModalAnimationService { - private readonly defaultDuration = 0.3; - private readonly defaultEase = 'power2.out'; - - openModal(modalElement: HTMLElement, overlayElement: HTMLElement) { - gsap.set(overlayElement, { opacity: 0, display: 'block' }); - gsap.set(modalElement, { - opacity: 0, - scale: 0.95, - y: 20, - display: 'block', - }); - - gsap.to(overlayElement, { - opacity: 1, - duration: this.defaultDuration, - ease: this.defaultEase, - }); - - gsap.to(modalElement, { - opacity: 1, - scale: 1, - y: 0, - duration: this.defaultDuration, - ease: this.defaultEase, - }); - } - - closeModal(modalElement: HTMLElement, overlayElement: HTMLElement, onComplete?: () => void) { - gsap.to([overlayElement, modalElement], { - opacity: 0, - duration: this.defaultDuration, - ease: this.defaultEase, - onComplete: () => { - gsap.set([overlayElement, modalElement], { display: 'none' }); - onComplete?.(); - }, - }); - - gsap.to(modalElement, { - scale: 0.95, - y: 20, - duration: this.defaultDuration, - ease: this.defaultEase, - }); - } -} diff --git a/frontend/src/app/shared/services/sound-initializer.service.ts b/frontend/src/app/shared/services/sound-initializer.service.ts deleted file mode 100644 index 47d09e0..0000000 --- a/frontend/src/app/shared/services/sound-initializer.service.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Injectable, Renderer2, RendererFactory2 } from '@angular/core'; - -@Injectable({ - providedIn: 'root', -}) -export class SoundInitializerService { - private renderer: Renderer2; - private observer: MutationObserver; - - constructor(rendererFactory: RendererFactory2) { - this.renderer = rendererFactory.createRenderer(null, null); - - this.observer = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - mutation.addedNodes.forEach((node) => { - if (node instanceof HTMLElement) { - this.processElement(node); - } - }); - }); - }); - } - - initialize() { - document.querySelectorAll('button, a').forEach((element) => { - if (!element.hasAttribute('appPlaySound')) { - this.renderer.setAttribute(element, 'appPlaySound', ''); - } - }); - - this.observer.observe(document.body, { - childList: true, - subtree: true, - }); - } - - private processElement(element: HTMLElement) { - if ( - (element.tagName === 'BUTTON' || element.tagName === 'A') && - !element.hasAttribute('appPlaySound') - ) { - this.renderer.setAttribute(element, 'appPlaySound', ''); - } - - element.querySelectorAll('button, a').forEach((child) => { - if (!child.hasAttribute('appPlaySound')) { - this.renderer.setAttribute(child, 'appPlaySound', ''); - } - }); - } -} diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts deleted file mode 100644 index c7df73a..0000000 --- a/frontend/src/environments/environment.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const environment = { - STRIPE_KEY: - 'pk_test_51QrePYIvCfqz7ANgMizBorPpVjJ8S6gcaL4yvcMQnVaKyReqcQ6jqaQEF7aDZbDu8rNVsTZrw8ABek4ToxQX7KZe00jpGh8naG', - apiUrl: window.location.origin + '/backend', -}; diff --git a/frontend/src/favicon.ico b/frontend/src/favicon.ico deleted file mode 100644 index 0a22de4..0000000 Binary files a/frontend/src/favicon.ico and /dev/null differ diff --git a/frontend/src/index.html b/frontend/src/index.html deleted file mode 100644 index 1c92a1e..0000000 --- a/frontend/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Trustworthy Casino - - - - - - - - diff --git a/frontend/src/main.ts b/frontend/src/main.ts deleted file mode 100644 index 17447a5..0000000 --- a/frontend/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app/app.config'; -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); diff --git a/frontend/src/proxy.conf.json b/frontend/src/proxy.conf.json deleted file mode 100644 index c9839a6..0000000 --- a/frontend/src/proxy.conf.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "/backend": { - "target": "http://localhost:8080/", - "secure": false, - "logLevel": "debug", - "pathRewrite": { - "^/backend": "" - }, - "changeOrigin": true - } -} diff --git a/frontend/src/styles.css b/frontend/src/styles.css deleted file mode 100644 index 57a0f6a..0000000 --- a/frontend/src/styles.css +++ /dev/null @@ -1,191 +0,0 @@ -@import 'tailwindcss'; - -@theme { - --color-deep-blue: #0a1219; - --color-deep-blue-light: #121e27; - --color-deep-blue-contrast: #1a2835; - - --color-emerald: #10b981; - --color-emerald-dark: #059669; - --color-emerald-light: #34d399; - - --color-text-primary: #ffffff; - --color-text-secondary: #94a3b8; - --color-text-tertiary: #64748b; - - --color-accent-yellow: #fbbf24; - --color-accent-red: #ef4444; - --color-accent-purple: #8b5cf6; -} - -body { - @apply bg-deep-blue text-text-primary h-full; -} - -button, -a { - @apply cursor-pointer active:scale-95 text-text-primary transition-all duration-200; -} - -.card { - @apply bg-deep-blue-contrast rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-300; -} - -.button-primary { - @apply bg-emerald hover:bg-emerald-dark text-text-primary transition-all duration-300 active:scale-95 rounded; -} - -.button-secondary { - @apply bg-deep-blue-light hover:bg-deep-blue-contrast w-full py-2 rounded my-2; -} - -.game-card-content { - @apply p-4; -} - -.nav-button { - @apply hidden lg:block absolute top-1/2 -translate-y-1/2 bg-deep-blue-contrast hover:bg-deep-blue-contrast/90 text-text-primary p-3 rounded-full opacity-0 group-hover:opacity-100 transition-all duration-300 shadow-lg hover:scale-110; -} - -.slider-container { - @apply flex transition-transform duration-500 ease-out; -} - -.slider-grid { - @apply min-w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4; -} - -.welcome-bonus { - @apply text-4xl sm:text-5xl lg:text-7xl font-extrabold text-emerald-light mb-3 sm:mb-4; -} - -.bonus-description { - @apply text-text-secondary text-base sm:text-lg mb-6 sm:mb-8; -} - -.section-heading { - @apply font-bold text-text-primary; -} - -.game-heading-sm { - @apply font-bold text-text-primary text-sm mb-2; -} - -.game-heading-xl { - @apply font-bold text-text-primary text-xl mb-2; -} - -.game-text { - @apply text-text-secondary text-sm mb-4; -} - -.stat-container { - @apply bg-deep-blue-contrast rounded-lg shadow-lg p-4 sm:p-6 text-center; -} - -.stat-number { - @apply text-xl sm:text-2xl font-bold text-emerald; -} - -.stat-text { - @apply text-text-secondary text-sm; -} - -.nav-brand { - @apply flex items-center text-text-primary text-xl font-semibold; -} - -.nav-link { - @apply px-3 py-2 rounded-md font-normal text-sm text-text-secondary hover:text-text-primary hover:bg-deep-blue-contrast transition-all duration-200; -} - -.nav-toggle { - @apply text-text-secondary hover:text-text-primary transition-colors duration-200; -} - -.nav-mobile-menu { - @apply p-2 pt-2 mb-4 space-y-1 bg-deep-blue-contrast rounded-b-lg; -} - -.nav-mobile-link { - @apply block px-3 py-2 rounded-md text-sm text-text-secondary hover:text-text-primary hover:bg-deep-blue-light transition-all duration-200; -} - -.footer-section { - @apply col-span-2 md:col-span-1; -} - -.footer-heading { - @apply text-text-primary text-sm font-semibold mb-4; -} - -.footer-link { - @apply text-text-secondary hover:text-text-primary text-sm transition-all duration-200; -} - -.footer-payment-method { - @apply bg-deep-blue rounded p-3 flex items-center justify-center space-x-2 hover:bg-deep-blue/50 transition-all duration-200; -} - -.footer-payment-icon { - @apply text-text-secondary text-lg; -} - -.footer-payment-text { - @apply text-text-secondary text-xs whitespace-nowrap; -} - -.footer-copyright { - @apply text-text-secondary text-sm; -} - -.footer-disclaimer { - @apply text-xs; -} - -.modal-bg { - @apply fixed inset-0 bg-black/80 backdrop-blur-sm z-50 focus:outline-none focus:ring-2 focus:ring-emerald-light; -} - -.modal-card { - @apply bg-deep-blue-contrast overflow-hidden hover:shadow-xl transition-shadow duration-300 p-6 rounded-xl shadow-2xl z-50 min-w-[300px] max-w-[400px] w-full mx-auto border border-deep-blue-light/20 fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2; -} - -.modal-heading { - @apply text-2xl font-bold text-text-primary mb-4; -} - -.modal-card input { - @apply w-full px-4 py-2.5 bg-deep-blue-light/50 text-white rounded-lg my-1 border border-deep-blue-light/30 focus:border-emerald/50 focus:ring-1 focus:ring-emerald/50 outline-none transition-all duration-200; -} - -.modal-card label { - @apply text-text-secondary text-sm font-medium mb-1 block; -} - -.modal-card button { - @apply transition-all duration-200; -} - -.modal-card .button-primary { - @apply bg-emerald hover:bg-emerald-dark text-text-primary transition-all duration-300 active:scale-95 shadow-lg shadow-emerald/20; -} - -.modal-card .button-secondary { - @apply bg-deep-blue-light/50 hover:bg-deep-blue-light w-full py-2.5 my-2 border border-deep-blue-light/30 hover:border-deep-blue-light/50; -} - -button, -a { - -webkit-tap-highlight-color: transparent; -} - -button[appPlaySound], -a[appPlaySound] { - cursor: pointer; -} - -button:not([appPlaySound]), -a:not([appPlaySound]) { - --add-sound-directive: true; -} diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json deleted file mode 100644 index 3775b37..0000000 --- a/frontend/tsconfig.app.json +++ /dev/null @@ -1,15 +0,0 @@ -/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ -/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json deleted file mode 100644 index faf0f24..0000000 --- a/frontend/tsconfig.json +++ /dev/null @@ -1,40 +0,0 @@ -/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ -/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ -{ - "compileOnSave": false, - "compilerOptions": { - "baseUrl": "./src", - "paths": { - "@service/*": ["app/service/*"], - "@environments/*": ["environments/*"], - "@shared/*": ["app/shared/*"], - "@blackjack/*": ["app/feature/game/blackjack/*"] - }, - "outDir": "./dist/out-tsc", - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "isolatedModules": true, - "esModuleInterop": true, - "sourceMap": true, - "declaration": false, - "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", - "lib": [ - "ES2022", - "dom" - ] - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/frontend/tsconfig.spec.json b/frontend/tsconfig.spec.json deleted file mode 100644 index 5fb748d..0000000 --- a/frontend/tsconfig.spec.json +++ /dev/null @@ -1,15 +0,0 @@ -/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ -/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ] - }, - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/justfile b/justfile deleted file mode 100644 index 4fc777c..0000000 --- a/justfile +++ /dev/null @@ -1,27 +0,0 @@ -# Info -info: - just --list - -# Starts the project in development mode -start: - command -v concurrently &> /dev/null || bun add -g concurrently - command -v watchexec &> /dev/null || brew install watchexec - docker compose up -d - conc -n "frontend,backend" "cd frontend && bun run start" "cd backend/ && watchexec -r -e java ./gradlew :bootRun" - -# Builds both the backend and frontend docker images (obv) -build: - just build-fe - just build-be - -# Builds the backend docker image -build-be: - docker buildx build -f backend/.docker/Dockerfile -t git.kjan.de/szut/casino-backend:latest backend - -# Builds the frontend docker image -build-fe: - docker buildx build -f frontend/.docker/Dockerfile -t git.kjan.de/szut/casino-frontend:latest frontend - -# Formats the code duh -format: - cd frontend && bunx prettier --write "src/**/*.{ts,html,css,scss}" diff --git a/release.config.cjs b/release.config.cjs deleted file mode 100644 index dffea8d..0000000 --- a/release.config.cjs +++ /dev/null @@ -1,64 +0,0 @@ -module.exports = { - branches: ["main"], - plugins: [ - [ - "@semantic-release/commit-analyzer", - { - preset: "angular", - releaseRules: [ - { type: "feat", release: "minor" }, - { type: "fix", release: "patch" }, - { type: "perf", release: "patch" }, - { type: "docs", release: "patch" }, - { type: "style", release: "patch" }, - { type: "refactor", release: "patch" }, - { type: "test", release: "patch" }, - { type: "chore", release: "patch" }, - { type: "ci", release: "patch" }, - { type: "build", release: "patch" }, - { type: "revert", release: "patch" }, - ], - }, - ], - [ - "@semantic-release/release-notes-generator", - { - preset: "conventionalcommits", - presetConfig: { - types: [ - { type: "feat", section: "Features", hidden: false }, - { type: "fix", section: "Bug Fixes", hidden: false }, - { - type: "perf", - section: "Performance Improvements", - hidden: false, - }, - { type: "docs", section: "Documentation", hidden: false }, - { type: "style", section: "Code Style", hidden: false }, - { type: "refactor", section: "Code Refactoring", hidden: false }, - { type: "test", section: "Tests", hidden: false }, - { type: "chore", section: "Chores", hidden: false }, - { type: "ci", section: "Continuous Integration", hidden: false }, - { type: "build", section: "Build System", hidden: false }, - { type: "revert", section: "Reverts", hidden: false }, - ], - }, - parserOpts: { - noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"], - }, - }, - ], - [ - "@semantic-release/changelog", - { - changelogFile: "CHANGELOG.md", - }, - ], - [ - "@saithodev/semantic-release-gitea", - { - giteaUrl: "https://git.kjan.de", - }, - ], - ], -}; diff --git a/renovate.json b/renovate.json deleted file mode 100644 index c183f9d..0000000 --- a/renovate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "local>Renovate/renovate-config" - ] -}